sketchucation logo sketchucation
    • Login
    🤑 SketchPlus 1.3 | 44 Tools for $15 until June 20th Buy Now

    REQ: Checking if components (solids) intersect

    Scheduled Pinned Locked Moved Plugins
    22 Posts 5 Posters 1.8k Views 5 Watching
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • B Offline
      Bobvandevoort
      last edited by

      Hi everyone,

      So I haven't been able to find a plugin that checks something crucial in my opinion.
      If you are designing a 3D object with movable parts it can sometimes be very important to check if solids (or components) intersect (or maybe touch). This is especially important if you have a high number of parts or moving parts. An example I can give of this is something I'm working on, it is a puzzle box.A puzzle box is a box that has sliding components on different sides on the box, called sliders. If you move when one these sliders you want ot be sure it doesn't get blocked by another part (aka intersecting), because if it's unintentionally blocked than you can't open the box.

      Something that would be even more usefull is if a part(component) could be moved (or rotated)along an axis until some part of it hits another component (this would make checking even easier).

      This can ofcourse be applied to much more cases, mostly mechanisms that need to be check if they having moving parts, a clock, a model engine, etc. To see if the device can actually operate.

      In the pdf file ans skp you can see what I mean with intersecting and touching.
      Intersecting1.pdf
      Intersecting.skp

      It would be even handier (also has a lot of other applications in building models) if you can move a component along the axes (either positive or negative) until it touches the next piece (component) and have it stop there. This easily shows if it can move along the intended path.
      It should check inner components touching and not just the surrounding (encompassing) parent component boxes.

      1 Reply Last reply Reply Quote 0
      • G Offline
        glro
        last edited by

        component check
        https://docs.google.com/file/d/0Bw8zdmaKDWIfNzdiNmQ5MmItOGJhNC00MzY1LWJmNjYtMzhlYWY3NzliYTkx/edit?hl=en_US%26amp;pli=1

        does part of the job you are asking for, as far as i understand

        detection based on the bounding box position is relatively easy to achieve, so this plugin could be hacked in the way you want it

        but if the component is not square, it is much more difficult

        you can also try SUsolid
        http://www.susolid.com/

        this plugin can detect any intersection of components, even if not square, but they must be solids

        1 Reply Last reply Reply Quote 0
        • BoxB Offline
          Box
          last edited by

          You might find Sketchy Physics useful.
          You could make your puzzles function and if they jam up you know there is a problem.


          SKPhysic.gif

          1 Reply Last reply Reply Quote 0
          • B Offline
            Bobvandevoort
            last edited by

            Thank you guys very much, the combination of SuSolid and Sketchy Physics should do the trick.

            Once I finish my work I'll show it 😉

            1 Reply Last reply Reply Quote 0
            • B Offline
              Bobvandevoort
              last edited by

              Oh btw if anyone has anymore more suggestions please share them.

              (using Sketchy Physics is going to be a lot of work, btw anyone no how to make objects only move when you drag/click them, so that they don't react to gravity)

              1 Reply Last reply Reply Quote 0
              • BoxB Offline
                Box
                last edited by

                You can turn gravity off or make it stronger etc in the Physics settings.

                Although it's worth noting what happens in 0 gravity.

                http://i155.photobucket.com/albums/s296/storeben/SU/Gravity.gif

                1 Reply Last reply Reply Quote 0
                • TIGT Offline
                  TIG Moderator
                  last edited by

                  Assuming they do/could overlap, then you need to check for geometry intersections.
                  Try this - you pass two arguments - references to a group or component-instance - returns ' true' if they do intersect|touch, or ' false' if there is no intersection [or 'nil' if incorrect arguments]: e.g. TIG.intersect?(e1, e2)

                  module TIG
                  	def self.intersect?(e1=nil, e2=nil)
                  		if e1.is_a?(Sketchup;;Group) || e1.is_a?(Sketchup;;ComponentInstance)
                  			if e1.is_a?(Sketchup;;Group)
                  				es1 = e1.entities
                  			else
                  				es1 = e1.definition.entities
                  			end
                  			fail = false
                  		else
                  			fail = true
                  		end
                  		if e2.is_a?(Sketchup;;Group) || e2.is_a?(Sketchup;;ComponentInstance)
                  			fail = false
                  		else
                  			fail = true
                  		end
                  		if fail
                  			puts("#{self}.intersect? requires references to two groups/component-instances.\nReturns 'true' [intersecting || touching] or 'false'.")
                  			return nil
                  		end
                  		ens = e1.parent.entities
                  		tr1 = e1.transformation
                  		grp = ens.add_group()
                  		grp.transform!(tr1) ### so can see cut lines IF erase! is disabled at the end !
                  		ges = grp.entities
                  		es1.intersect_with(true, tr1, ges, tr1, true, e2)
                  		if ges[0]
                  			int = true
                  		else
                  			int = false
                  		end
                  		grp.erase!
                  		return int
                  	end
                  end
                  

                  Note that they do not need to be 'solids', but a check for that could be added...

                  TIG

                  1 Reply Last reply Reply Quote 0
                  • B Offline
                    Bobvandevoort
                    last edited by

                    @tig said:

                    Assuming they do/could overlap, then you need to check for geometry intersections.
                    Try this - you pass two arguments - references to a group or component-instance - returns ' true' if they do intersect|touch, or ' false' if there is no intersection [or 'nil' if incorrect arguments]: e.g. TIG.intersect?(e1, e2)

                    module TIG
                    > 	def self.intersect?(e1=nil, e2=nil)
                    > 		if e1.is_a?(Sketchup;;Group) || e1.is_a?(Sketchup;;ComponentInstance)
                    > 			if e1.is_a?(Sketchup;;Group)
                    > 				es1 = e1.entities
                    > 			else
                    > 				es1 = e1.definition.entities
                    > 			end
                    > 			fail = false
                    > 		else
                    > 			fail = true
                    > 		end
                    > 		if e2.is_a?(Sketchup;;Group) || e2.is_a?(Sketchup;;ComponentInstance)
                    > 			fail = false
                    > 		else
                    > 			fail = true
                    > 		end
                    > 		if fail
                    > 			puts("#{self}.intersect? requires references to two groups/component-instances.\nReturns 'true' [intersecting || touching] or 'false'.")
                    > 			return nil
                    > 		end
                    > 		ens = e1.parent.entities
                    > 		tr1 = e1.transformation
                    > 		grp = ens.add_group()
                    > 		grp.transform!(tr1) ### so can see cut lines IF erase! is disabled at the end !
                    > 		ges = grp.entities
                    > 		es1.intersect_with(true, tr1, ges, tr1, true, e2)
                    > 		if ges[0]
                    > 			int = true
                    > 		else
                    > 			int = false
                    > 		end
                    > 		grp.erase!
                    > 		return int
                    > 	end
                    > end
                    

                    Note that they do not need to be 'solids', but a check for that could be added...

                    That seems really nice and cool but I've never worked with ruby nor the ruby interface in sketchup.
                    I do have some basic coding skills in C (and some other languages).

                    Does it matter that instead of having groups that I have components (as far as I understood it doesn't).

                    SUSolids sees all my components as solids at the moment so if that is what you mean by solid than yes all my components are solids.

                    Furthermore I understand the code more or less up till the checking if there're actually 2 components selected. After that it's a bit unclear how it checks for the intersection (it seems like you're using the intersection tool but the arguments are unclear).

                    Further it should be possible to just use a for loop to check the whole model for intersections right?


                    One other thing would it be possible to check for only touching between just 2 components (multiple would be better) in a certain plain (of 1 of the components).

                    So let me explain that a bit more correctly by first telling what I want to use the check for. I want to make a move command/script/tool that moves 1 a component along an axis (both direction being possible) until it collides with another surface/component. This means that if a component is moved along the x-axis it should only look if it's touching any other components in the x-direction (or an yz-plane). Meaning if I have a rod in a cylinder with their longitudinal axis in the x-axis and I let the rod be moved/translated along the x-axis than even if their walls are touching in the y or z direction it should stop the translation. The translation should be stopped as soon as an intersection or a touch at base of the rod touches and yz-plane is detected.

                    1 Reply Last reply Reply Quote 0
                    • TIGT Offline
                      TIG Moderator
                      last edited by

                      My example code checks if any two given groups OR component-instances 'intersect'.
                      It only works if the two things are in the same entities context, but I assume you haven't nested things...
                      So TIG.intersect(e1,e2) returns 'true' or 'false' if they intersect|touch or if they are separate, it returns 'nil' if you pass wrong arguments.
                      They do not need to be solids for this test.
                      To test all objects in a context try this [NOTE: you also need to have pre-loaded the ' TIG.intersect? code !]

                      module TIG
                      	def self.intersectALL()
                      		model=Sketchup.active_model
                      		ss=model.selection
                      		ents=model.active_entities
                      		ss.clear
                      		gps=ents.grep(Sketchup;;Group)
                      		ins=ents.grep(Sketchup;;ComponentInstance)
                      		ens=gps+ins
                      		ens.uniq!
                      		ens.compact!
                      		(ens.length-1).times{|i|
                      			(ens.length-1).times{|j|
                      				next if j==i
                      				if self.intersect?(ens[i], ens[j])
                      					ss.add(ens[i])
                      					ss.add(ens[j])
                      				end
                      			}
                      		}
                      		puts "Any intersecting groups/component-intsnces are highlighted..."
                      	end
                      end
                      

                      To run it use TIG.intersectALL
                      All groups/component-instances that intersect or touch are highlighted...
                      It highlights all groups/component-intsances that intersect...

                      TIG

                      1 Reply Last reply Reply Quote 0
                      • B Offline
                        Bobvandevoort
                        last edited by

                        Hey TIG,

                        Thanks a lot again that is really helpful 😄

                        Three more things though, one I do have nested components (otherwise my model is unmanageble) which makes it troublesome to use it like this in my final script. (btw I only use components)

                        Secondly what if I just want to find intersecting components (groups/element) and not also touching ones.

                        The last thing is I now understand both codes except for a part concerning the first script

                          grp = ens.add_group()
                              grp.transform!(tr1) ### so can see cut lines IF erase! is disabled at the end !
                              ges = grp.entities
                              es1.intersect_with(true, tr1, ges, tr1, true, e2)
                              if ges[0]
                                 int = true
                              else
                                 int = false
                              end
                        

                        A few things here, sometimes the intersection lines fail to show up. (this is when I have nested component but these components are not touching or intersecting anything)

                        the intersect_with is still unclear to me.
                        we make a group of the first entity 1 which we call grp
                        then do a transformation (now is this a simple translation or a true transformation and how should I envision that in skp)
                        We say ges= the entities that were transformed
                        Now we intersect all the entities in ges with e2, which if an intersect occurs removes all elements from ges as for as I understand. However what's the reason the es1.intersect_with.

                        Also why can't we by example use something like this

                        
                        
                        result = e1.intersect(e2)
                        if result == nil
                           int = false
                        else 
                            int = true
                        

                        Please keep in mind this is my first time doing any programming in ruby and for SU, so I had to read up on some of the coding before I could reply.

                        Thank you very much for the help 😄

                        1 Reply Last reply Reply Quote 0
                        • TIGT Offline
                          TIG Moderator
                          last edited by

                          My 'simple' example expects both of the passed objects [group/component-instance] to be in the same context - just as you might when doing the intersection manually on two selected objects.
                          If they are not in the same entities-context they probably won't intersect logically, unless you somehow apply both of their 'transformations' in the intersection-tests - I'll have to think about that...


                          Here's a breakdown of the code...

                          grp = ens.add_group() This adds a temporary group to contain the intersection edges, if any
                          grp.transform!(tr1) ### so can see cut lines IF erase! is disabled at the end ! It's as the ### note says - it moves the intersection lines back to where you'd expect them to be, rather than at the ORIGIN - if you erase! the grp you never see it...
                          ges = grp.entities A reference to the grp entities context
                          es1.intersect_with(true, tr1, ges, tr1, true, e2) The complicated 'intersect_with' - the first passed group/component-instance 'e1' [referenced earlier as 'es1'] is intersected with the second passed group/component-instance 'e2' [final argument in the ()], the other arguments in the () are 'true' to tell it to put the intersected geometry into another context, 'ges' sets the destination of the intersected geometry [the grp's entities], 'tr1' the transformation of 'e1', 'true' to include any hidden objects in the intersection, and as mentioned before 'e2' the second object that is being intersected with...
                          if ges[0] int = true else int = false end This final part tests for any entities inside the 'grp' entities-context 'ges': if so 'int' is 'true' otherwise it's 'false'...
                          Not included in your snippet - it then does grp.erase! to remove the temporary group, and return 'int'...


                          It would be difficult to test for a full intersection rather than a touching.
                          If you make two box groups and place them so the definitely overlap and select them and do a context-menu 'intersect-selection' you'll get a set of edges - visible if you move the two groups away.
                          If you move a group so that 'kiss' - i.e. touch on a face - and repeat the intersect-selection, you still get geometry where they touch.
                          There is no easily identifiable difference between the two - the full-intersection set is clearly '3d' BUT a touching set of edges could be equally complex...

                          The only way to test otherwise... is to consider every vertex in a group and see if its position [adjusted for the container's transformation AND the potentially intersected second container's transformation] is inside the second object - probably with a 'raytest'.
                          But even then it'd be quite possible to intersect two objects in such a way that no vertices from one are inside the other, BUT a true intersection still exists !


                          Any suggestions on how a full-intersection versus a touching-intersection can be determined would be appreciated...

                          TIG

                          1 Reply Last reply Reply Quote 0
                          • B Offline
                            Bobvandevoort
                            last edited by

                            Thanks for the really awesome explanation.

                            I know a way that works (and just finished writing it) however it requires the pro version.

                            I wrote it "ruby code editor" plugin and there for used the selection in the model to set the two components. (link http://www.alexschreyer.net/projects/sketchup-ruby-code-editor/)

                            it works good so far only got a little error when I try to turn the material red of the intersecting component part.

                            mod = Sketchup.active_model # Open model
                            ent = mod.entities # All entities in model
                            sel = mod.selection # Current selection
                             instance1 = sel[0]
                             instance2 = sel[1]
                             ci_def = instance1.definition 
                             tr1 = instance1.transformation
                             test1 = Sketchup.active_model.entities.add_instance ci_def, tr1
                             ci_def2 = instance2.definition 
                             tr2 = instance2.transformation
                             test2 = Sketchup.active_model.entities.add_instance ci_def2, tr2
                             result = test1.intersect(test2) # I can delete this later using something like an observer but would have to figure out how that works, also need to figure out how to make this work for more than 2 components and I need to figure out how to do it (multi)nested components.
                             cnt = result.entities.count 
                            if  cnt > 0
                             int=true
                             result.material='red'
                               # result.definition.entities.each {|ent|           ###When I run this in the plugin in console I get the following error "Done. Ruby says; uninitialized constant AS_RubyEditor;;RubyEditor;;Face"
                               #   if ent.is_a? Sketchup;;Face
                               #    Face.material = 'red' #Sketchup;;Color.new(255, 0, 0)
                               #  end}
                            else
                             int=false
                            end
                            
                            #return int
                            
                            

                            If I run the code normally I get the following output "Done. Ruby says: red"
                            However the faces aren't red they just stay the original color.

                            1 Reply Last reply Reply Quote 0
                            • G Offline
                              glro
                              last edited by

                              @bobvandevoort said:

                              ..
                              If I run the code normally I get the following output "Done. Ruby says: red"
                              However the faces aren't red they just stay the original color.

                              they are red, actually... but inside. Faces a reversed

                              1 Reply Last reply Reply Quote 0
                              • TIGT Offline
                                TIG Moderator
                                last edited by

                                It's not Face.material = 'red'
                                it'd be ent.material = 'red'

                                TIG

                                1 Reply Last reply Reply Quote 0
                                • P Offline
                                  pgarmyn
                                  last edited by

                                  @TIG
                                  In method def self.intersectALL()

                                  (ens.length-1).times{|i|
                                           (ens.length-1).times{|j|
                                              next if j<=i # in place of  ; next if j==i
                                              if self.intersect?(ens[i], ens[j])
                                                 ss.add(ens[i])
                                                 ss.add(ens[j])
                                              end
                                           }
                                  

                                  next if j<=i ( in place of next if j==i )
                                  prevents double checking (slower) and double results.
                                  If intersect?(ens[1], ens[2]) has been tested, then we don't have to test intersect?(ens[2], ens[1])

                                  1 Reply Last reply Reply Quote 0
                                  • G Offline
                                    glro
                                    last edited by

                                    @pgarmyn said:

                                    @TIG
                                    In method def self.intersectALL()

                                    (ens.length-1).times{|i|
                                    >          (ens.length-1).times{|j|
                                    >             next if j<=i # in place of  ; next if j==i
                                    >             if self.intersect?(ens[i], ens[j])
                                    >                ss.add(ens[i])
                                    >                ss.add(ens[j])
                                    >             end
                                    >          }
                                    

                                    next if j<=i ( in place of next if j==i )
                                    prevents double checking (slower) and double results.
                                    If intersect?(ens[1], ens[2]) has been tested, then we don't have to test intersect?(ens[2], ens[1])

                                    I don't know why, but neither TIG's version, nor yours, works on my computer

                                    this is how i changed the code:

                                    		model=Sketchup.active_model
                                    		ss=model.selection
                                    		ents=model.active_entities
                                    		ss.clear
                                    		gps=ents.grep(Sketchup;;Group)
                                    		ins=ents.grep(Sketchup;;ComponentInstance)
                                    		ens=gps+ins
                                    		ens.uniq!
                                    		ens.compact!
                                    		for i in (0..ens.length-1)
                                    			for j in ((i+1)..ens.length-1)
                                    				if TIG.intersect?(ens[i], ens[j])
                                    					ss.add(ens[i])
                                    					ss.add(ens[j])
                                    				end
                                    			end
                                    		end
                                            puts "Any intersecting groups/component-instances are highlighted..."
                                    

                                    length-1 because it because i begins at 0...
                                    and the i+1 to avoid comparing i to itself

                                    is this version much slower than yours?

                                    1 Reply Last reply Reply Quote 0
                                    • P Offline
                                      pgarmyn
                                      last edited by

                                      @giro

                                      		model=Sketchup.active_model
                                      		ss=model.selection
                                      		ents=model.active_entities
                                      		ss.clear
                                      		gps=ents.grep(Sketchup;;Group)
                                      		ins=ents.grep(Sketchup;;ComponentInstance)
                                      		ens=gps+ins
                                      		ens.uniq!
                                      		ens.compact!
                                      		for i in (0..ens.length-2)  ############changed from length-1 to length-2
                                      			for j in ((i+1)..ens.length-1)
                                      				if TIG.intersect?(ens[i], ens[j])
                                      					ss.add(ens[i])
                                      					ss.add(ens[j])
                                      				end
                                      			end
                                      		end
                                              puts "Any intersecting groups/component-instances are highlighted..."
                                      

                                      I think, in this case, the last TIG.intersect?(ens[i], ens[j]) is with i=length-2 and j=length-1
                                      Otherwise j = i+1 will become ens.length : for 5 elements (0 to 4) in ens, j will be 5.

                                      1 Reply Last reply Reply Quote 0
                                      • G Offline
                                        glro
                                        last edited by

                                        @pgarmyn said:

                                        @glro

                                        I think, in this case, the last TIG.intersect?(ens[i], ens[j]) is with i=length-2 and j=length-1
                                        Otherwise j = i+1 will become ens.length : for 5 elements (0 to 4) in ens, j will be 5.

                                        yes, i agree
                                        it works in both cases, but your version should be faster

                                        1 Reply Last reply Reply Quote 0
                                        • B Offline
                                          Bobvandevoort
                                          last edited by

                                          @tig said:

                                          It's not Face.material = 'red'
                                          it'd be ent.material = 'red'

                                          Thanks this solved it 😄

                                          Btw there's a way to do it with the intersect_with function and rule out most of the touching elements.
                                          Any 3d volume needs at least 4 faces, so do a face count for ges and see if it equals 4 or more.
                                          I know there probably some odd situations where it would still only be touching but then you could check if the faces form a solid if it doesn't form a solid it's a touch (I think this should be a correct way to implement this).

                                          Let me know your thought about this method 😉

                                          (in any real 3d modeling you only need to find volumetric intersections and if you also want to find out of they are thouching we already have the method you previously described.

                                          Everybody else thanks for the response and sorry for the delay on my side with responding, I have been away for 2 days.

                                          1 Reply Last reply Reply Quote 0
                                          • P Offline
                                            pgarmyn
                                            last edited by

                                            @bobvandevoort
                                            To rule out most of the elements :
                                            You can exclude elements based on boundingbox values :
                                            Elements a and b won't intersect
                                            If a.bounds.max.x < b.bounds.min.x
                                            If a.bounds.min.x > b.bounds.max.x
                                            If ..... 4 other tests with .y and .z

                                            I'm not shure if this will speed up your code. I can imagen that those tests are also done by the (faster) intersect method of the API

                                            1 Reply Last reply Reply Quote 0
                                            • 1
                                            • 2
                                            • 1 / 2
                                            • First post
                                              Last post
                                            Buy SketchPlus
                                            Buy SUbD
                                            Buy WrapR
                                            Buy eBook
                                            Buy Modelur
                                            Buy Vertex Tools
                                            Buy SketchCuisine
                                            Buy FormFonts

                                            Advertisement