sketchucation logo sketchucation
    • Login
    πŸ€‘ SketchPlus 1.3 | 44 Tools for $15 until June 20th Buy Now

    Geom.intersect_line_line question

    Scheduled Pinned Locked Moved Developers' Forum
    15 Posts 4 Posters 557 Views
    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
      Brett McAllister
      last edited by

      model = Sketchup.active_model
      entities = model.entities
      
      dpoint_1=[-3.989142.m, 3.877123.m, -0.m]
      dpoint_2=[-3.989142.m, -3.647636.m, -0.m]
      curve_array=[[-3.989142.m, 3.877123.m, -0.m],[-4.457867.m, 3.358428.m, -0.m],[-4.853319.m, 2.781918.m, -0.m],
      [-5.16845.m, 2.157867.m, -0.m],[-5.397644.m, 1.4974.m, -0.m],[-5.536815.m, 0.812289.m, -0.m],
      [-5.583482.m, 0.114744.m, -0.m],[-5.536815.m, -0.582801.m, -0.m],[-5.397644.m, -1.267913.m, -0.m],
      [-5.16845.m, -1.92838.m, -0.m],[-4.853319.m, -2.55243.m, -0.m],[-4.457867.m, -3.128941.m, -0.m],[-3.989142.m, -3.647636.m, -0.m]]
      curve_center=[-0.347015.m, 0.114744.m, -0.m]
      center= [-5.583482.m, 0.114744.m, -0.m]
      offset1_vec =center.vector_to dpoint_1
      offset2_vec =center.vector_to dpoint_2
      offset1 = center.offset offset1_vec,(0.2.m)
      offset2 = center.offset offset2_vec,(0.2.m)
      line1_vector = center.vector_to curve_center 
      line2_vector = center.vector_to curve_center 
      line1 = [offset1,line1_vector]
      line2 = [offset2,line2_vector]	
      
      entities.add_curve(curve_array)
      entities.add_cline(offset1,line1_vector)
      entities.add_cline(offset2,line2_vector)
      curve_array_length =(curve_array.length)-1
      
      curve_array_length.times do |point|
      line = [curve_array.at(point),curve_array.at(point +1) ]	
      pt1 = Geom.intersect_line_line(line, line1)
      pt2 = Geom.intersect_line_line(line, line2)
      puts "pt1;#{pt1}"
      puts "pt2;#{pt1}"
      end
      

      Hi Guys

      Just wondering why the above code sample returns an intersection with each code block iteration.
      If it was working correctly it should return 2 point3d's instead every line comparison is showing up as an intersection?
      I am sure there must be something basic that I have missed.
      Some times another set of eyes works wonders.

      Cheers Brett

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

        It is working correctly.
        A 'line' *isn'*t an 'edge'.
        An 'edge' has a 'line' - a 'line' is simply an array of a point and a vector = [point, vector] which stretches infinitely.
        So if you have an edge intersecting a coplanar curve its line will intersect with the line of every edge in the curve, unless a curve-edge is exactly parallel with the intersecting edge - as then their lines will never intersect...
        I think what you actually want is to test for an edge intersecting other edges...
        First you narrow it down to the list of intersection-points you are getting - make an array of them as you collect them.
        Now iterate again through these points and check if they actually fall 'on' the 'intersecting-edge' itself rather than just its 'line'.
        To do this write a simple sub-method inside your main code...

        def is_point_on_edge?(point,edge)
          dis=edge.length
          spt=edge.start.position
          ept=edge.end.position
          if point.distance(spt)<=dis and point.distance(ept)<=dis
            return true
          else
            return false
          end
        end
        

        to use it simply use it inside a block iterating the points
        intersecting_points << point if is_point_on_edge?(point,edge)
        The test is true if the edges intersect at a vertex - Note how this could return two identical points for a start or end when that is the intersection point as a vertex is still 'on' the edge - after making the array of points [0/1/2/3/4 long (with possible duplicates at vertices) for an 'arc', but for a 'curve' that could zigzag this could be any number as it's edges pass across the intersecting edge...]you can then simply test for equality of any of them in the intersecting_points array and keep just one if so...
        is_point_on_edge? assumes you already established that 'point' is on 'edge.line' - you could readily combine the two tests into one if you wanted to... πŸ€“

        TIG

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

          Thanks for the reply and suggestion Tig.
          For some reason I thought if you use two point3d's to form a line, you created a line segment, instead of an infinite line.
          The dangers of coding when your tired.

          Regards

          Brett

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

            @brett mcallister said:

            Thanks for the reply and suggestion Tig.
            For some reason I thought if you use two point3d's to form a line, you created a line segment, instead of an infinite line.
            The dangers of coding when your tired.

            Regards

            Brett

            When you specify an edge by two points [confusingly it IS referred to as a 'line' in entities.add_line(pt0,pt1) πŸ˜’ ] then what you get IS an edge [or a 'line-segment' as you call it]... BUT when you get that edge's 'line' with edge.line then it becomes as infinitely long 'thing' - a vector through a fixed point... that could intersect with other 'lines' - to get 'physical' intersections of edges use a method like I outlined..........

            TIG

            1 Reply Last reply Reply Quote 0
            • H Offline
              honkinberry
              last edited by

              Here's my confusion with the Geom.intersect_line_line --
              when I'm processing a large file, that seems to be a huge amount of additional processing, with it always assuming the two lines are infinite.
              In particular,

              
              Geom.intersect_line_line(edge1.line,edge2.line)
              
              

              I can appreciate why it treats them as infinite, but what about this:

              
              Geom.intersect_line_line(edge1.vertices,edge2.vertices)
              
              

              If it's going to accept the vertices as parameters, why can't it treat them as fixed length?

              Put that on my wishlist.

              --J

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

                A 3 item array, and the special kinds of arrays - i.e. a point and a vector both have xyz values.
                Many of Sketchup tools also accept a vertex as if it were a point, doing the vertex.position conversion for you.
                You can confuse Sketchup by passing something other than a the correct 'types' as a 'line' and thereby having it think it is one.
                A 'line' is a two item array containing a point and a vector [or the equivalent arrays for these].
                Every edge has a 'line' consisting of its start vertex position [point] and the vector from that point to its end vertex position.
                A 'line' in geometry is considered infinite.
                So two 'lines' might intersect and return a point, but that intersection-point may well not be on either of the edges that own those 'lines'...
                An edge has two vertices - so edge.vertices is effectively returning an array of two xyz arrays [vertex, vertex].
                This array of two vertices could be confused as the [point, vector] needed to define that 'line' BUT the second element is a NOT a vector, or anything equivalent to the edge's vector, so the result will be wrong !
                If you want to intersect the 'lines' of two edges and find out if its intersection-point [if successful] is physically on one [or both] of those two edges then there are several examples of code to do that. Rick Wilson did one to check if such a point was between the two points defined by the edge's start.position and end.position - i.e. it was on the edge, will additional flags for ignoring/accepting if the point were exactly at a start/end position...
                You don't have the right kind of arrays passed from two 'edge.vertices' to get a meaningful intersection with another pair of 'edge.vertices' - there is no vector information in there - that's why edge.line was invented ! It is relatively straightforward to get the two edges' lines, see if they intersect, and then see if the intersection-point falls on neither, one or two of the edges, even checking for start/end-point being coincident with it as valid or not...

                TIG

                1 Reply Last reply Reply Quote 0
                • H Offline
                  honkinberry
                  last edited by

                  Thanks for clarifying a bit.
                  It's just difficult for the likes of me, coming from a strong background in the CAD realm (AutoCAD and Revit).
                  In AutoCAD, you have intersect(p1, p2, p3, p4, INF), where INF is the flag to treat the line segments as infinite.
                  Further, you can very quickly build a selection of all objects within certain bounds.
                  So coming from that experience, it just feels like I'm having to needlessly iterate through all entities in a model to perform some simple intersection checking.
                  I've got a routine that does exactly what you describe, but with 1,500 edges in a model (which seems like a ridiculously small set), checking them all against each other just seems to take too long.

                  --J

                  1 Reply Last reply Reply Quote 0
                  • thomthomT Offline
                    thomthom
                    last edited by

                    @honkinberry said:

                    I've got a routine that does exactly what you describe, but with 1,500 edges in a model (which seems like a ridiculously small set), checking them all against each other just seems to take too long.

                    What is that routine? Ruby is slow and it behaves in strange ways that I've often find surprising ways to optimize code. If you have a snippet we can have a look and have a stab at it.

                    Thomas Thomassen β€” SketchUp Monkey & Coding addict
                    List of my plugins and link to the CookieWare fund

                    1 Reply Last reply Reply Quote 0
                    • H Offline
                      honkinberry
                      last edited by

                      So given an array of edges 'elist' (imported from AutoCAD), I'm checking for intersections.

                      
                      elist.each do |e1|
                      	# so given this line, we look for intersections, to amend [p1,p2] to [p1,px,pn,p2]
                      	p1 = e1.start.position
                      	p2 = e1.end.position
                      	plist = [p1,p2]
                      	line1 = e1.line # [point . vector]
                      
                      	# for this line segment, compare to all other edges
                      	elist.each do |e2|
                      		if ( e1 != e2 ) # only if not the same edge of course
                      			line2 = e2.line # [point . vector]
                      			v1 = line1[1] # vector
                      			v2 = line2[1] # vector
                      					
                      			if ( v1 != v2 ) # if vectors are differnet, they aren't parallel
                      				int = Geom.intersect_line_line(line1,line2) # but assumes infinite!
                      				if ( int ) # make sure it's on both lines, and not an endpoint of line1
                      					z1 = e2.start.position
                      					z2 = e2.end.position
                      
                      					if ( !plist.include?(int) ) # not end point or already found
                      						if ( pointonline(int,p1,p2) ) # and on line1
                      							if ( pointonline(int,z1,z2) ) # and on line2
                      								# so adding our intersection to line 1
                      								plist << int
                      							end # if co-linear2
                      						end # if co-linear1
                      					end # if not end point
                      				end # if intersection
                      			end # if not parallel
                      
                      		end # if not same segment
                      	end # subloop
                      
                      	# ... do stuff with amended plist ...
                      end # entity loop
                      
                      

                      Missing is a standard helper function 'pointonline' which checks if given point falls on the given line segment.
                      Given about 1,500 edges, it seems it can easily take 30 seconds, which just feels far too long for my taste.
                      Many thanks if you have any tips to optimize it!

                      --J

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

                        As I thought I explained...
                        Rick Wilson already made a function called something like
                        point.between_points?(pt1, pt2, cond)
                        So to see if a point on a an edge use that passing the edge.start.position and edge.end.position as the arguments - returns true or false: the ' cond' determines if the point that is 'exactly on' the edge's start/end is be be regarded as 'between' the given points...

                        I posted an example of this three years ago!
                        http://sketchucation.com/forums/viewtopic.php?p=243509#p243509

                        Note that changing/adding-to the built-in API class methods is probably not the best way to do it... BUT you can easily use the principal to make your own equivalent of this method, wrapped in your own module/class/methods...

                        TIG

                        1 Reply Last reply Reply Quote 0
                        • thomthomT Offline
                          thomthom
                          last edited by

                          Here's my version of it: https://bitbucket.org/thomthom/tt-library-2/src/56b237cae78615e19712faf22980293879916793/TT_Lib2/point3d.rb?at=Version%202.8#cl-28

                          Thomas Thomassen β€” SketchUp Monkey & Coding addict
                          List of my plugins and link to the CookieWare fund

                          1 Reply Last reply Reply Quote 0
                          • H Offline
                            honkinberry
                            last edited by

                            Sorry, guess I wasn't clear.
                            I have the pointonline function, and yes, that's easy, hence why I didn't bother including it.
                            My issue, is that in a model with 1,500 edges, the afore posted routine takes over 30 seconds to complete.
                            What I was hoping to do, was to optimize that routine if possible. As near as I can tell, I have to iterate through all edges, and compare each to all other edges, perform an intersect_line_line, and then check if that point falls on both edges. Correct?
                            I tried adding some basic coordinate validation, checking the X and Y coordinates of each edge end point first, to see if an intersection might be possible, but just took even more processing time.
                            I'm about to check the exact processing hit for each of the key tests, to see what is the big hangup, but thought I'd post what I have so far to see if there's any thing that jumps out as slow.

                            --J

                            1 Reply Last reply Reply Quote 0
                            • thomthomT Offline
                              thomthom
                              last edited by

                              Yea, Ruby is so slow that extra checks might just make it slower. Perhaps you can use the BoundingBox class?

                              In general, try to make the API methods to the most work as then it's performed in C++.

                              Thomas Thomassen β€” SketchUp Monkey & Coding addict
                              List of my plugins and link to the CookieWare fund

                              1 Reply Last reply Reply Quote 0
                              • H Offline
                                honkinberry
                                last edited by

                                I've tried a few variations now.
                                added a BoundingBox intersection testing, and if that hits, then do an intersect_line_line.
                                That ends up taking about 10% more time.
                                Then on a whim, I even removed the Vector checking, that saves time.
                                So no matter what I try, indeed, it seems the fastest is to get to the intersect_line_line as quickly as possible, as that's even faster than comparing the vectors first.

                                The really unfortunate part, now, is that I've found in trying to add a progress bar at the status line, that just seems to add a huge amount of time to the operation. I'd rather have a spinning pinwheel for 30 seconds than a progress bar for 2 minutes. I guess I could try optimizing the progress bar function, it looks like it's updating the status bar text every iteration, regardless of whether the percentage has changed.

                                Thanks as always for the tips!

                                --J

                                1 Reply Last reply Reply Quote 0
                                • thomthomT Offline
                                  thomthom
                                  last edited by

                                  Then it sounds like moving to an Ruby C Extension is what might give real performance improvements.

                                  Thomas Thomassen β€” SketchUp Monkey & Coding addict
                                  List of my plugins and link to the CookieWare fund

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

                                  Advertisement