Snap point to point



  • Surprisingly I couldn't find an answer to this:

    When dragging a point or a contour from a point, is it possible to have it snapped to other points (and how)?


  • admin

    like a point is snapping to a guide? maybe you have to elaborate your question a bit more.

    but you could create a tool where the dragging is snapped to all available points.

    as a pro-tip: you can subclass a Editing Tool and overwrite modifyDraggingPoint(point, delta).

    Good luck



  • I'd like to position a point exactly on top of another point (while dragging a contour the first point is a part of). That's even simpler than snapping to a guide, since snapping to a line means jumping to the closest point on a line, while in my case I just want my point to snap to a single point.

    So a new tool is required?



  • Hi @oribendor,

    At one point I had tried writing a script that would snap to vertical metrics. As an example for you, I've made some adaptations to that script to make it align to other points. Works pretty well, and you can adjust the threshold. Off the top of my head, I'm not sure how to make handles’s relative position to their on-curve points stable while aligning, but this is a solid start. Let me know if you figure that aspect out. Here's a demo video and the script. Run it as a start-up script in RF so the observer is always running. If anyone has any tips for streamlining this type of code, I'd be interested in seeing that, too.

    from mojo.events import addObserver
    
    threshold = 20
    
    class point2PointSnapper():
        
        '''
        A start-up script that makes oncurve points snap to each other within a certain threshold.
        '''
        
        def __init__(self):
            
            addObserver(self, "mouseDragged", "mouseDragged")
            
        def mouseDragged(self, notification):
            # Location of mouse when dragged
            mouse_x = notification['point'].x
            mouse_y = notification['point'].y
            # print(notification)
            # print(mouse_x)
            # print(mouse_y)
            
            g = CurrentGlyph()
            
            if g != None:
                
                if g.selection != ():
                    if len(g.selection) == 1:
                
                        # Registering all the points in the glyph you may want to align to.
                        al_pts = []
                        for c in g:
                            for pt in c.points:
                                # You probably only want to align to on-curve points.
                                if pt.type != "offcurve":
                                        al_pts.append((pt.x, pt.y))
                                        
                        for pt in g.selection:
                            # Aligning a point to itself is... mindblowing, but useless, so we'll disregard current selection as alignable.
                            al_pts.remove((pt.x, pt.y))
                                            
                            pt.x = mouse_x
                            pt.y = mouse_y
                            # For each point you could align to, snap-to if nearby.
                            for al_pt in al_pts:
                                if  al_pt[0] - threshold < mouse_x < al_pt[0] + threshold:
                                    if al_pt[1] - threshold < mouse_y < al_pt[1] + threshold:
                                        print("snapping single point")
                                        pt.x = al_pt[0]
                                        pt.y = al_pt[1]
                
    point2PointSnapper()
    

  • admin

    cool!

    an different approache! I like it


Log in to reply