def insert_point(self, x, y):
        
        """ Inserts a point on the path at the mouse location.
        
        We first need to check if the mouse location is on the path.
        Inserting point is time intensive and experimental.
        
        """
        
        try: 
            bezier = _ctx.ximport("bezier")
        except:
            from nodebox.graphics import bezier
        
        # Do a number of checks distributed along the path.
        # Keep the one closest to the actual mouse location.
        # Ten checks works fast but leads to imprecision in sharp corners
        # and curves closely located next to each other.
        # I prefer the slower but more stable approach.
        n = 100
        closest = None
        dx0 = float(INFINITY) 
        dy0 = float(INFINITY)
        for i in range(n):
            t = float(i)/n
            pt = self.path.point(t)
            dx = abs(pt.x-x)
            dy = abs(pt.y-y)
            if dx+dy <= dx0+dy0:
                dx0 = dx
                dy0 = dy
                closest = t

        # Next, scan the area around the approximation.
        # If the closest point is located at 0.2 on the path,
        # we need to scan between 0.1 and 0.3 for a better
        # approximation. If 1.5 was the best guess, scan
        # 1.40, 1.41 ... 1.59 and so on.
        # Each decimal precision takes 20 iterations.                
        decimals = [3,4]
        for d in decimals:
            d = 1.0/pow(10,d)
            
            for i in range(20):
                t = closest-d + float(i)*d*0.1
                if t < 0.0: t = 1.0+t
                if t > 1.0: t = t-1.0
                pt = self.path.point(t)
                dx = abs(pt.x-x)
                dy = abs(pt.y-y)
                if dx <= dx0 and dy <= dy0:
                    dx0 = dx
                    dy0 = dy
                    closest_precise = t
            
            closest = closest_precise   

        # Update the points list with the inserted point.
        p = bezier.insert_point(self.path, closest_precise)
        i, t, pt = bezier._locate(self.path, closest_precise)
        i += 1
        pt = PathElement()
        pt.cmd = p[i].cmd
        pt.x = p[i].x
        pt.y = p[i].y
        pt.ctrl1 = Point(p[i].ctrl1.x, p[i].ctrl1.y)
        pt.ctrl2 = Point(p[i].ctrl2.x, p[i].ctrl2.y)
        pt.freehand = False
        self._points.insert(i, pt)
        self._points[i-1].ctrl1 = Point(p[i-1].ctrl1.x, p[i-1].ctrl1.y)
        self._points[i+1].ctrl1 = Point(p[i+1].ctrl1.x, p[i+1].ctrl1.y)
        self._points[i+1].ctrl2 = Point(p[i+1].ctrl2.x, p[i+1].ctrl2.y)
Exemple #2
0
 def addpoint(self, t):
     import bezier
     self._nsBezierPath = bezier.insert_point(self, t)._nsBezierPath
     self._segment_cache = None
Exemple #3
0
 def addpoint(self, t):
     import bezier
     self._elements = bezier.insert_point(self, t)._elements
     self._segment_cache = None
Exemple #4
0
    def insert_point(self, x, y):
        
        """ Inserts a point on the path at the mouse location.
        
        We first need to check if the mouse location is on the path.
        Inserting point is time intensive and experimental.
        
        """
        
        try: 
            bezier = _ctx.ximport("bezier")
        except:
            from nodebox.graphics import bezier
        
        # Do a number of checks distributed along the path.
        # Keep the one closest to the actual mouse location.
        # Ten checks works fast but leads to imprecision in sharp corners
        # and curves closely located next to each other.
        # I prefer the slower but more stable approach.
        n = 100
        closest = None
        dx0 = float(INFINITY) 
        dy0 = float(INFINITY)
        for i in range(n):
            t = float(i) / n
            pt = self.path.point(t)
            dx = abs(pt.x - x)
            dy = abs(pt.y - y)
            if (dx + dy) <= (dx0 + dy0):
                dx0 = dx
                dy0 = dy
                closest = t

        # Next, scan the area around the approximation.
        # If the closest point is located at 0.2 on the path,
        # we need to scan between 0.1 and 0.3 for a better
        # approximation. If 1.5 was the best guess, scan
        # 1.40, 1.41 ... 1.59 and so on.
        # Each decimal precision takes 20 iterations.                
        decimals = [3,4]
        for d in decimals:
            d = 1.0 / pow(10, d)
            
            for i in range(20):
                t = (closest - d) + (float(i) * d * 0.1)

                if t < 0.0: t = 1.0+t

                if t > 1.0: t = t-1.0

                pt = self.path.point(t)
                dx = abs(pt.x - x)
                dy = abs(pt.y - y)

                if dx <= dx0 and dy <= dy0:
                    dx0 = dx
                    dy0 = dy
                    closest_precise = t
            
            closest = closest_precise   

        # Update the points list with the inserted point.
        p = bezier.insert_point(self.path, closest_precise)
        i, t, pt = bezier._locate(self.path, closest_precise)
        i += 1
        pt = PathElement()
        pt.cmd = p[i].cmd
        pt.x = p[i].x
        pt.y = p[i].y
        pt.ctrl1 = Point(p[i].ctrl1.x, p[i].ctrl1.y)
        pt.ctrl2 = Point(p[i].ctrl2.x, p[i].ctrl2.y)
        pt.freehand = False
        self._points.insert(i, pt)
        self._points[i-1].ctrl1 = Point(p[i-1].ctrl1.x, p[i-1].ctrl1.y)
        self._points[i+1].ctrl1 = Point(p[i+1].ctrl1.x, p[i+1].ctrl1.y)
        self._points[i+1].ctrl2 = Point(p[i+1].ctrl2.x, p[i+1].ctrl2.y)