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

    Pick closest point of a polyline

    Scheduled Pinned Locked Moved Developers' Forum
    3 Posts 2 Posters 680 Views 2 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.
    • T Offline
      tjrob
      last edited by

      I have a polyline with arbitrary 3-d structure, drawn as a series of cline-s. Inside my DragTool.mouse_move I want to determine the closest point on this polyline corresponding to the mouse position. Yes, this is in general ambiguous, but I don't care, and any solution will do. Indeed, as long as it is "close", the user will deal with it by moving the mouse closer to the polyline to remove the ambiguity. Basically I am placing a ComponentInstance along the polyline, moving it as the user moves the mouse, but it's always constrained to line on the polyline (oriented, too, but that's not the issue, and once I have the segment and point of the polyline I'll also have the orientation).

      Any suggestion how to do this?

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

        Let's start simple...
        With just ONE cline.
        This has a start_point and an end_point.
        From those you can also find its "line" line=[start_point, start_point.vector_to(end_point)]
        You can get the mouse's position as a mpoint.
        [This is the tricky bit - see API for InputPoints and PickHelpers]
        You can use the API methods to determine the mpoint projected to line
        ppoint=mpoint.project_to_line(line)

        So this is the mouse's location projected to the cline's "line"...

        BUT it might not fall 'on' the cline itself...
        You need to do some checking...
        OK if ppoint == start_point || ppoint == end_point ### it's on one of the cline's 'ends'
        OK if ppoint.vector_to(start_point).normalize != ppoint.vector_to(start_point).normalize ### it's on the cline itself because the vectors are reversed.
        BUT if ppoint.vector_to(start_point).normalize == ppoint.vector_to(start_point).normalize ### it's on the "line" BUT off the cline itself, so you need to take the nearest 'end' of the cline instead...
        if ppoint.distance(start_point) < ppoint.distance(end_point)
        ppoint=start_point.clone
        else
        ppoint=end_point.clone
        end

        So now we have a system for projecting the mouse-point onto a single cline.

        If you have a collection of clines you need to determine the one that is 'nearest' the mouse-point]..
        To do this you need to get the "line" of every cline in turn, and use the above code to get the projected-point of each, then get the distance of the mouse-point to each of those projected-points - the shortest distance gives you point to use... If you have a distance==0 then the cursor is on the cline, so you can break as there is no point testing further.

        TIG

        1 Reply Last reply Reply Quote 0
        • T Offline
          tjrob
          last edited by

          @tig said:

          Let's start simple...

          Thanks, TIG, for the suggestion. Unfortunately it does not work very well at all, basically because in 3D the mouse represents a ray, not a point. Sketchup generates a point via InputPoint and PickHelper using a heuristic that does not work very well at all in this application.

          I have a method that works well:

          • get the mouse ray via view.pickray(x,y)

          • loop over all segments of the polyline

          • compute the position along the line containing the segment, where the ray is closest to the line

          • trim that to the endpoints of the segment

          • compute distance from the resulting point to the ray

          • remember the closest one

          • now I have the segment and location within the segment of the mouse

          • generate the Geom::Transform for that location
            Basically this represents the centerline of a particle accelerator, and the code is inside my custom DragTool, using the mouse to place an object along the centerline; so the object is constrained to lie on the centerline, and its local z-axis is aligned with the centerline where it is located. For <= 200 segments this tracks the mouse quite well; for 1000 segments it takes about 1 second to catch up. That's acceptable for now; ultimately I may optimize it. I'm rather surprised that this much Ruby computation is acceptable.

          If a segment is parallel to the pickray, the math will divide by zero. So my code disallows any segment that is nearly parallel to the pickray. This makes sense, as the user cannot possibly select a position along such a segment; use the middle button to rotate the display so the desired position is visible.

          I ended the centerline with a half-infinite straight line. SketchUp cannot draw that (or rather, it tries to do so, zooming out so much that it's useless). So I split the final segment in two, with the first being half as long as the preceding centerline; the code does not display the final segment.

          The next challenge is to generalize this to include segments that are circular arcs (so far the code is limited to radius=0)....

          If anyone wants my code, or references to the geometrical calculations I'm using, just ask.

          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