Ejemplo n.º 1
0
    def draw_freehand(self):
        
        """ Freehand sketching.
        """
        
        if _ctx._ns["mousedown"]:
            
            x, y = mouse()
            if self.show_grid:
                x, y = self.grid.snap(x, y)
            
            if self.freehand_move == True:
                cmd = MOVETO
                self.freehand_move = False
            else:
                cmd = LINETO
            
            # Add a new LINETO to the path,
            # except when starting to draw,
            # then a MOVETO is added to the path.
            pt = PathElement()
            if cmd != MOVETO:
                pt.freehand = True # Used when mixed with curve drawing.
            else:
                pt.freehand = False
            pt.cmd = cmd
            pt.x = x
            pt.y = y
            pt.ctrl1 = Point(x,y)
            pt.ctrl2 = Point(x,y)
            self._points.append(pt)
            
            # Draw the current location of the cursor.
            r = 4
            _ctx.nofill()
            _ctx.stroke(self.handle_color)
            _ctx.oval(pt.x-r, pt.y-r, r*2, r*2)
            _ctx.fontsize(9)
            _ctx.fill(self.handle_color)
            _ctx.text(" ("+str(int(pt.x))+", "+str(int(pt.y))+")", pt.x+r, pt.y)
        
            self._dirty = True
        
        else:

            # Export the updated drawing,
            # remember to do a MOVETO on the next interaction.
            self.freehand_move = True
            if self._dirty:
                self._points[-1].freehand = False
                self.export_svg()
                self._dirty = False
Ejemplo n.º 2
0
    def draw_freehand(self):
        
        """ Freehand sketching.
        """
        
        if _ctx._ns["mousedown"]:
            
            x, y = mouse()
            if self.show_grid:
                x, y = self.grid.snap(x, y)
            
            if self.freehand_move == True:
                cmd = MOVETO
                self.freehand_move = False
            else:
                cmd = LINETO
            
            # Add a new LINETO to the path,
            # except when starting to draw,
            # then a MOVETO is added to the path.
            pt = PathElement()
            if cmd != MOVETO:
                pt.freehand = True # Used when mixed with curve drawing.
            else:
                pt.freehand = False
            pt.cmd = cmd
            pt.x = x
            pt.y = y
            pt.ctrl1 = Point(x,y)
            pt.ctrl2 = Point(x,y)
            self._points.append(pt)
            
            # Draw the current location of the cursor.
            r = 4
            _ctx.nofill()
            _ctx.stroke(self.handle_color)
            _ctx.oval(pt.x-r, pt.y-r, r*2, r*2)
            _ctx.fontsize(9)
            _ctx.fill(self.handle_color)
            _ctx.text(" ("+str(int(pt.x))+", "+str(int(pt.y))+")", pt.x+r, pt.y)
        
            self._dirty = True
        
        else:

            # Export the updated drawing,
            # remember to do a MOVETO on the next interaction.
            self.freehand_move = True
            if self._dirty:
                self._points[-1].freehand = False
                self.export_svg()
                self._dirty = False
Ejemplo n.º 3
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)
Ejemplo n.º 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)