sketchucation logo sketchucation
    • Login
    ℹ️ Licensed Extensions | FredoBatch, ElevationProfile, FredoSketch, LayOps, MatSim and Pic2Shape will require license from Sept 1st More Info

    Intersect ray and circle in 3D?

    Scheduled Pinned Locked Moved Developers' Forum
    14 Posts 6 Posters 2.6k Views 6 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.
    • thomthomT Offline
      thomthom
      last edited by

      Anton: Why did you create a custom distance() method?

      Sam: Thank you for providing bonus method with a sphere. 😄

      I've not gotten around to test this yet, but I'll do so when I get home. Thank you very much everyone.

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

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

        Some off the wall observations...
        We know the circle's center, radius and normal.
        Therefore we know the circle's plane.
        If the origin for the test 'ray' is always the circle's center
        Actually we don't need the 'ray' at all, just the 'vector'...
        The test needs to establish if the vector runs along the plane - if it doesn't there is no point to be got !
        We know the circle's center, radius and normal, and the vector, so we can easily find the point where the center projects to the circumference [i.e. radially]... OR nil...
        So to put it into one compacted lump assuming with have a 'circle' to pass

        def center_projected_radially_by_vector(circle, vector)
          ### add trapping here for valid circle, vector etc...
          center=circle.center
          normal=circle.normal
          radius=circle.radius
          if center.offset(vector).on_plane?([center, normal])
            return center.offset(vector, radius)
          else
            return nil
          end
        end
        

        The method center_projected_radially_by_vector(circle, vector) will return a Point3d that is on the circumference, OR nil if the vector is non-planar.
        Of course this ignores the 'segmented' nature of a SketchUp Circle - I have assumed you want a point on the real circumference - if not, then this 'intersection' can be done by convoluted calculation, BUT a @model.raytest()[/ruby] could find the intersection-point '[ruby:vjmyuykr]ipt[/ruby:vjmyuykr]' if the vector is planar; [ruby:vjmyuykr]rayt=@model.raytest([center, vector])[/ruby:vjmyuykr] where [ruby:vjmyuykr]ipt=rayt[0] if circle.edges.include?(rayt[1][-1])[/ruby:vjmyuykr]
        If intervening preexisting geometry might intercede in the raytest etc then add extra tests and loop until it works or the rayt==nil ?

        TIG

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

          Good point TIG. That should also work.

          @tig said:

          Of course this ignores the 'segmented' nature of a SketchUp Circle - I have assumed you want a point on the real circumference - if not, then this 'intersection' can be done by convoluted calculation, BUT a @model.raytest()[/ruby] could find the intersection-point '[ruby:1ceso981]ipt[/ruby:1ceso981]' if the vector is planar; [ruby:1ceso981]rayt=@model.raytest([center, vector])[/ruby:1ceso981] where [ruby:1ceso981]ipt=rayt[0] if circle.edges.include?(rayt[1][-1])[/ruby:1ceso981]
          If intervening preexisting geometry might intercede in the raytest etc then add extra tests and loop until it works or the rayt==nil ?

          No - no entities are involved. This is pure geometry. When I say ray and line I mean that ray is a point with a vector, line indicate an infinite line (like the Geom module docs describe) and circle is a true geometric circle (hence I defined it as centre, normal and radius - though I probably should have been more explicit).

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

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

            A minor refactoring of TIGs solution and the code becomes even simpler.

            <span class="syntaxdefault"><br />def&nbsp;center_projected_radially_by_vector</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">centre</span><span class="syntaxkeyword">,&nbsp;</span><span class="syntaxdefault">normal</span><span class="syntaxkeyword">,&nbsp;</span><span class="syntaxdefault">radius</span><span class="syntaxkeyword">,&nbsp;</span><span class="syntaxdefault">vector</span><span class="syntaxkeyword">)<br />&nbsp;&nbsp;</span><span class="syntaxdefault">point&nbsp;</span><span class="syntaxkeyword">=&nbsp;</span><span class="syntaxdefault">center</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">offset</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">vector</span><span class="syntaxkeyword">,&nbsp;</span><span class="syntaxdefault">radius</span><span class="syntaxkeyword">)<br />&nbsp;&nbsp;(&nbsp;</span><span class="syntaxdefault">point</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">on_plane</span><span class="syntaxkeyword">?([</span><span class="syntaxdefault">center</span><span class="syntaxkeyword">,&nbsp;</span><span class="syntaxdefault">normal</span><span class="syntaxkeyword">])&nbsp;)&nbsp;?&nbsp;</span><span class="syntaxdefault">point&nbsp;</span><span class="syntaxkeyword">;&nbsp;</span><span class="syntaxdefault">nil<br />end<br /></span>
            

            I guess my initial question was to broad to what I actually wanted to achieve. Offsetting the centre by the vector is face-palm simple.

            I'll try this out in my project later.

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

            1 Reply Last reply Reply Quote 0
            • sdmitchS Offline
              sdmitch
              last edited by

              Anton's solution works as long as the ray vector and the plane normal are not perpendicular. If they are then the ray will never intersect the plane. If that is the case, the ray point must be on the plane and then it becomes a line_sphere intersection problem.

              Nothing is worthless, it can always be used as a bad example.

              http://sdmitch.blogspot.com/

              1 Reply Last reply Reply Quote 0
              • A Offline
                Anton_S
                last edited by

                @thomthom said:

                Anton: Why did you create a custom distance() method?

                Cause i don't trust SketchUp's native distance function. I heard that it rounds up the result or something...

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

                  @anton_s said:

                  @thomthom said:

                  Anton: Why did you create a custom distance() method?

                  Cause i don't trust SketchUp's native distance function. I heard that it rounds up the result or something...

                  It doesn't. But it does return a Length object, and if you compare two Length objects it uses SketchUp's tolerance. SketchUp does that because floats are inherently inaccurate and you need to compare with a little bit of tolerance. Check out this page if you're not familiar with floating point precision: http://floating-point-gui.de/

                  If you do want to bypass SU's internal tolerance just convert the Length to a Float, using .to_f.

                  Generally you will want to use SketchUp's own methods, not only to match up the tolerance, but also because SketchUp does it's calculations in C++, while doing the same in Ruby is horribly slow!

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

                  1 Reply Last reply Reply Quote 0
                  • A Offline
                    Anton_S
                    last edited by

                    <span class="syntaxdefault">module Author </span><span class="syntaxcomment"># <--<< Author's proprietary toplevel namespace<br /><br /></span><span class="syntaxdefault">  class </span><span class="syntaxkeyword"><<</span><span class="syntaxdefault"> self </span><span class="syntaxcomment"># <--<< THIS module's anonymous singleton proxy class<br /><br /></span><span class="syntaxdefault">    </span><span class="syntaxcomment"># Compute intersection between the ray & circle in 3D space.<br /></span><span class="syntaxdefault">    </span><span class="syntaxcomment"># Args;;<br /></span><span class="syntaxdefault">    </span><span class="syntaxcomment">#   ray    - [point, vector]<br /></span><span class="syntaxdefault">    </span><span class="syntaxcomment">#   circle - [center, radius, normal]<br /></span><span class="syntaxdefault">    </span><span class="syntaxcomment"># Returns;;<br /></span><span class="syntaxdefault">    </span><span class="syntaxcomment">#   Point3d object of the intersection if it does intersect - nil otherwise.<br /></span><span class="syntaxdefault">    </span><span class="syntaxcomment">#<br /></span><span class="syntaxdefault">    def intersectRayCircle</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">ray</span><span class="syntaxkeyword">,</span><span class="syntaxdefault"> circle</span><span class="syntaxkeyword">)<br /></span><span class="syntaxdefault">      </span><span class="syntaxcomment"># Get circle plane<br /></span><span class="syntaxdefault">      center </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> Geom</span><span class="syntaxkeyword">;;</span><span class="syntaxdefault">Point3d</span><span class="syntaxkeyword">.new(</span><span class="syntaxdefault">circle</span><span class="syntaxkeyword">[</span><span class="syntaxdefault">0</span><span class="syntaxkeyword">])<br /></span><span class="syntaxdefault">      radius </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> circle</span><span class="syntaxkeyword">[</span><span class="syntaxdefault">1</span><span class="syntaxkeyword">]<br /></span><span class="syntaxdefault">      normal </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> Geom</span><span class="syntaxkeyword">;;</span><span class="syntaxdefault">Vector3d</span><span class="syntaxkeyword">.new(</span><span class="syntaxdefault">circle</span><span class="syntaxkeyword">[</span><span class="syntaxdefault">2</span><span class="syntaxkeyword">])<br /></span><span class="syntaxdefault">      plane  </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">[</span><span class="syntaxdefault">center</span><span class="syntaxkeyword">,</span><span class="syntaxdefault"> normal</span><span class="syntaxkeyword">]<br /></span><span class="syntaxdefault">      </span><span class="syntaxcomment"># Get ray/line<br /></span><span class="syntaxdefault">      point  </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> Geom</span><span class="syntaxkeyword">;;</span><span class="syntaxdefault">Point3d</span><span class="syntaxkeyword">.new(</span><span class="syntaxdefault">ray</span><span class="syntaxkeyword">[</span><span class="syntaxdefault">0</span><span class="syntaxkeyword">])<br /></span><span class="syntaxdefault">      vector </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> Geom</span><span class="syntaxkeyword">;;</span><span class="syntaxdefault">Vector3d</span><span class="syntaxkeyword">.new(</span><span class="syntaxdefault">ray</span><span class="syntaxkeyword">[</span><span class="syntaxdefault">1</span><span class="syntaxkeyword">])<br /></span><span class="syntaxdefault">      line   </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">[</span><span class="syntaxdefault">point</span><span class="syntaxkeyword">,</span><span class="syntaxdefault"> vector</span><span class="syntaxkeyword">]<br /></span><span class="syntaxdefault">      </span><span class="syntaxcomment"># Check for intersection<br /></span><span class="syntaxdefault">      xpoint </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> Geom</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">intersect_line_plane</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">line</span><span class="syntaxkeyword">,</span><span class="syntaxdefault"> plane</span><span class="syntaxkeyword">)<br /></span><span class="syntaxdefault">      return nil if </span><span class="syntaxkeyword">(</span><span class="syntaxdefault">xpoint </span><span class="syntaxkeyword">==</span><span class="syntaxdefault"> nil</span><span class="syntaxkeyword">)<br /></span><span class="syntaxdefault">      </span><span class="syntaxcomment"># Check, if xpoint distance to center equals to radius<br /></span><span class="syntaxdefault">      </span><span class="syntaxkeyword">(</span><span class="syntaxdefault">xpoint</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">distance</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">center</span><span class="syntaxkeyword">)</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">==</span><span class="syntaxdefault"> radius</span><span class="syntaxkeyword">)</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">?</span><span class="syntaxdefault"> xpoint </span><span class="syntaxkeyword">;</span><span class="syntaxdefault"> nil<br />    end<br /><br />  end </span><span class="syntaxcomment"># proxy class<br /><br /></span><span class="syntaxdefault">end </span><span class="syntaxcomment"># Module Author &nbsp;</span><span class="syntaxdefault"></span>
                    

                    Example:

                    <span class="syntaxdefault"></span><span class="syntaxcomment"># intersectRayCircle([point, vector], [center, radius, normal])<br /></span><span class="syntaxdefault">Author</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">intersectRayCircle</span><span class="syntaxkeyword">([</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">[</span><span class="syntaxdefault">0</span><span class="syntaxkeyword">,</span><span class="syntaxdefault">0</span><span class="syntaxkeyword">,</span><span class="syntaxdefault">0</span><span class="syntaxkeyword">],</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">[</span><span class="syntaxdefault">1</span><span class="syntaxkeyword">,</span><span class="syntaxdefault">0</span><span class="syntaxkeyword">,</span><span class="syntaxdefault">0</span><span class="syntaxkeyword">]</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">],</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">[</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">[</span><span class="syntaxdefault">10</span><span class="syntaxkeyword">,</span><span class="syntaxdefault">0</span><span class="syntaxkeyword">,</span><span class="syntaxdefault">5</span><span class="syntaxkeyword">],</span><span class="syntaxdefault"> 5</span><span class="syntaxkeyword">,</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">[</span><span class="syntaxdefault">1</span><span class="syntaxkeyword">,</span><span class="syntaxdefault">0</span><span class="syntaxkeyword">,</span><span class="syntaxdefault">0</span><span class="syntaxkeyword">]</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">])<br /></span><span class="syntaxcomment"># Returs; Point3d(10,0,0)    &nbsp;</span><span class="syntaxdefault"></span>
                    

                    I've tested it in simple conditions, I'm not sure if it will work in any conditions. 💚

                    1 Reply Last reply Reply Quote 0
                    • A Offline
                      Anton_S
                      last edited by

                      @thomthom said:

                      It does return a Length object, and if you compare two Length objects it uses SketchUp's tolerance.

                      Okay, script edited


                      @thomthom said:

                      Generally you will want to use SketchUp's own methods, not only to match up the tolerance, but also because SketchUp does it's calculations in C++, while doing the same in Ruby is horribly slow!

                      👍
                      Good Point, and Interesting!!!


                      If I compile C distance function to .so and use it in SetchUp, it will be faster than the distance function written in Ruby, right? Just a question for clerification.

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

                        @anton_s said:

                        If I compile C distance function to .so and use it in SetchUp, it will be faster than the distance function written in Ruby, right? Just a question for clerification.

                        Not sure it would, if you wrote a C Extension that took two Geom::Point3d objects and computed the distance then you've effectively duplicated SketchUp's method. And SketchUp is written in C++, a subset of C, so I don't know what kind of improvements you'd expect.

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

                        1 Reply Last reply Reply Quote 0
                        • AdamBA Offline
                          AdamB
                          last edited by

                          The best optimization, is to avoid doing work at all. Work on your algorithm first.

                          (C++ is a superset of C)

                          Here's some numbers I've simply plucked out of thin air:

                          Invoking a C++ method from Ruby costs 500+ instructions.

                          If the work you do in the method is less than this (calc distance = ~10 instructions), the cost of invocation swamps the cost of evaluation.

                          Adam

                          Developer of LightUp Click for website

                          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