NSBezierPath (Modifying Paths)
Hello Everyone, I am working on something small just to learn with and I have been trying to figure this out for a while. The end result that I am looking for is this Draw A straight line click the line and drag to make that line curve Now I have been able to get all of this to work aside from one thing. If you draw a curve then go to draw another the first one is not remembered. Code: http://paste.lisp.org/display/74870 I know it is my call to removeAllPaths on line 59 of the code pasted at the URL above. I know that i need to use the elementsAtIndex: and elementsAtIndex:index associatedPoints:points to modify the points rather than remove them all However what I do not know is where I would get this Index to use. Any assistance would be appreciated. Thanks, Joseph Crawford ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: NSBezierPath (Modifying Paths)
On Feb 4, 2009, at 07:35, Joseph Crawford wrote: Draw A straight line click the line and drag to make that line curve Now I have been able to get all of this to work aside from one thing. If you draw a curve then go to draw another the first one is not remembered. Code: http://paste.lisp.org/display/74870 I know it is my call to removeAllPaths on line 59 of the code pasted at the URL above. I know that i need to use the elementsAtIndex: and elementsAtIndex:index associatedPoints:points to modify the points rather than remove them all However what I do not know is where I would get this Index to use. Your general approach doesn't make a lot of sense to me. 'drawRect' is for drawing, and it's a really bad idea to be constructing parts of your data model in that method. (In particular, drawRect can get called multiple times without the mouse being dragged, and each time it's going to add more points to the existing path. Not to mention the fact that it'll add these points to *all* the paths, not just the latest one.) I'd suggest: -- Keep your path array just for paths that are fully created. That is, in mouseUp but not before, add the current path to the path array. -- Don't bother trying to *change* the NSBezierPath object that's in the process of being created, just create a brand new one each time you go through mouseDragged. Performance would be the only reason not to do this, but you're not going to have a performance problem anytime soon. If you plan to be able to edit the paths later, then NSBezierPath isn't the best choice as a data structure. -- Do nothing in drawRect except drawing. If you keep the in progress path out of the path array till it's done, you can also draw it in (say) a different color, which would be a nice visual cue. -- Change 'numberOfClicks' to something like 'numberOfControlPointsDrawn' (with values 0, 1 and 2) for clarity. The number of clicks isn't actually important, but the number of control points dragged out is. While this approach to drawing paths isn't terrible, it *is* terribly modal. If I was to draw a straight line and then wanted to draw another path without making the first one a curve, how would do I do that? If I started dragging out a path and wanted to get rid of it and start a new one, how would I do that? ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: NSBezierPath (Modifying Paths)
Quincey, You make some very good points. Let me first start out by saying I was doing ALL the path work in drawRect: based on someone telling me that was the best practice, I then had a few people including you tell me that is not the case. I am not worried about performance right now that is true. I am also not worried about you drawing a curve and then wanting to draw a straight line. This is all just messing around trying to replicate the capabilities of the curve tool in many drawing applications, I already saw how to replicate the drawing of a line and that would be a different tool to choose from. What would you suggest I look into for wanting to modify the points? I had this working perfectly with a tempPath for the dragging and actually had it grey in color and when it was drawn it was done so in black (the visual queue) but was told that I could do it with only one path which is why I was looking into modifying the path elements. When I have one point the dragging operation always added more and more points which led to the line being drawn with every drag and that was not the wanted solution. Thanks, Joseph Crawford On Feb 4, 2009, at 12:59 PM, Quincey Morris wrote: On Feb 4, 2009, at 07:35, Joseph Crawford wrote: Draw A straight line click the line and drag to make that line curve Now I have been able to get all of this to work aside from one thing. If you draw a curve then go to draw another the first one is not remembered. Code: http://paste.lisp.org/display/74870 I know it is my call to removeAllPaths on line 59 of the code pasted at the URL above. I know that i need to use the elementsAtIndex: and elementsAtIndex:index associatedPoints:points to modify the points rather than remove them all However what I do not know is where I would get this Index to use. Your general approach doesn't make a lot of sense to me. 'drawRect' is for drawing, and it's a really bad idea to be constructing parts of your data model in that method. (In particular, drawRect can get called multiple times without the mouse being dragged, and each time it's going to add more points to the existing path. Not to mention the fact that it'll add these points to *all* the paths, not just the latest one.) I'd suggest: -- Keep your path array just for paths that are fully created. That is, in mouseUp but not before, add the current path to the path array. -- Don't bother trying to *change* the NSBezierPath object that's in the process of being created, just create a brand new one each time you go through mouseDragged. Performance would be the only reason not to do this, but you're not going to have a performance problem anytime soon. If you plan to be able to edit the paths later, then NSBezierPath isn't the best choice as a data structure. -- Do nothing in drawRect except drawing. If you keep the in progress path out of the path array till it's done, you can also draw it in (say) a different color, which would be a nice visual cue. -- Change 'numberOfClicks' to something like 'numberOfControlPointsDrawn' (with values 0, 1 and 2) for clarity. The number of clicks isn't actually important, but the number of control points dragged out is. While this approach to drawing paths isn't terrible, it *is* terribly modal. If I was to draw a straight line and then wanted to draw another path without making the first one a curve, how would do I do that? If I started dragging out a path and wanted to get rid of it and start a new one, how would I do that? ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/codebowl%40gmail.com This email sent to codeb...@gmail.com ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: NSBezierPath (Modifying Paths)
On Feb 4, 2009, at 10:54, Joseph Crawford wrote: This is all just messing around trying to replicate the capabilities of the curve tool in many drawing applications, I already saw how to replicate the drawing of a line and that would be a different tool to choose from. What would you suggest I look into for wanting to modify the points? I had this working perfectly with a tempPath for the dragging and actually had it grey in color and when it was drawn it was done so in black (the visual queue) but was told that I could do it with only one path which is why I was looking into modifying the path elements. When I have one point the dragging operation always added more and more points which led to the line being drawn with every drag and that was not the wanted solution. You *could* take an approach where your underlying data model consisted of just NSBezierPath objects. Then, drawing in your user interface would be easy -- just stroke the underlying paths. However, the *usability* isn't great, and would likely get worse as you added more functionality. (For example, by following this approach, you already lost the ability to draw new stuff in gray.) You'll find things easier, though, if you design your own objects for your underlying data model. How you would break it down depends on what you're trying to achieve. Perhaps each path/contour/outline is an object, which contains an array of segment objects, and each segment has 2 or 4 points. Maybe you have curved and straight line segment objects in a path object, or maybe you have only curved segments in a curved path and only straight line segments in a polyline path. Maybe you have to keep track of whether your paths are open or closed. At some point you'll need to work out where to keep track of the stroke width and color, probably. It all depends what you want. Most likely you'd want to use NSBezierPaths for actual drawing. It wouldn't be wrong to create *those* on the fly in your drawRect, used for drawing and discarded, but if that was anything but trivial you might want to consider pre-creating these drawing paths and having them ready before you get to the actual drawing. Again, it depends. The messing around part is fine, but I think you'll find that it very quickly becomes a data model design exercise PLUS a user interface design exercise, neither of them trivial. (Cue Graham Cox...) ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: NSBezierPath (Modifying Paths)
I just thought I'd throw my 2ยข worth in here, since I've been down this very long road in great detail while building DrawKit, so I've learned a thing or two about this. On 5 Feb 2009, at 5:54 am, Joseph Crawford wrote: You make some very good points. Let me first start out by saying I was doing ALL the path work in drawRect: based on someone telling me that was the best practice, I then had a few people including you tell me that is not the case. Absolutely wrong. -drawRect: is solely and unequivocally for drawing *only*. If you find yourself adding or removing points to a path in there, you've made an error in design. This is all just messing around trying to replicate the capabilities of the curve tool in many drawing applications, I already saw how to replicate the drawing of a line and that would be a different tool to choose from. Some apps don't do this all that well actually. For my money, the approach that Inkscape (and DrawKit) takes is the one I've found the more intuitive. This uses a mouse down to set the on-path point, then the immediately following drag to set the off-path (control) point for the two control points that are either side of the just-placed on-path point. These two control points and the on-path point always form a straight line, thus the curve that passes through the on-path point is tangent to this line. This ensures that the join between elements of the curve is smooth. If you don't want that you can go back and change the points later, but for initially laying down a curve, this is rapid and graceful. The next on-path point along then requires a new mouse- down, which implies that during the intervening mouse-up period, you need to attach the current end-point of the curve to the mouse and use mouse-moved events. Because of that, using a view's mouseDown/ mouseDragged/mouseUp methods is terribly unwieldy, so I found that making your own tracking loop and entering it from the mouseDown only, and staying in it until you've finished the entire curve works much better. This forms a short-term temporary mode where you are constructing your curved path. The next problem is how do you get out of this mode? I do it in several ways. If you double-click at the end of the path it finishes, or if you click on the first point of the path, forming a closed path, it finishes, or if you hit Escape, it finishes. Having the modal loop here allows you to make use of four mouse gestures (down, drag, up, move) instead of the usual three. It also allows you to use a different modal loop for others kinds of drawing tool - lines and polygons require a different series of gestures to create them. There are other niceties too, like allowing modifier keys to constrain drags in various ways, such as forcing the angles between a control point and the on-path point to be whole intervals, or temporarily toggling snap to grid plus a few others. Real drawing apps need these sorts of things, so while you will probably feel that's overkill at this stage, it may be worth thinking about how you'd incorporate those into your design. What would you suggest I look into for wanting to modify the points? Essentially all that Cocoa provides is the - elementAtIndex:associatedPoints: method and its inverse. That's about as minimalistic as it gets - all of the other interactive stuff needed you'll have to write. In DrawKit I tackle this in several stages. First, I have a category on NSBezierPath that extends the low-level tools available for basic path manipulation. This provides methods for identifying the different points on a path relative to one another (for example if dragging a curve element control point you need to also modify its mate, bearing in mind that if the next or previous element isn't a curve it doesn't exist, etc). The highest level method in this category is the method: - (void) moveControlPointPartcode:(int) pc toPoint:(NSPoint) p colinear:(BOOL) colin coradial:(BOOL) corad constrainAngle:(BOOL) acon; Which wraps up all the nasty tricky stuff into one method which basically implements moving of any point on any path, so you'd call this in a loop (or from mouseDragged:) when dragging. I have other classes that call this when they are responding to user edits in their paths, but basically this one does the grunt work. By the way you could use this if you want, DrawKit is free under a BSD license. I had this working perfectly with a tempPath for the dragging and actually had it grey in color and when it was drawn it was done so in black (the visual queue) but was told that I could do it with only one path which is why I was looking into modifying the path elements. When I have one point the dragging operation always added more and more points which led to the line being drawn with every drag and that was not the wanted solution. NSBezierPath is not
Re: NSBezierPath (Modifying Paths)
On 05/02/2009, at 10:11 AM, Graham Cox wrote: You can download a very bare-bones demo app that also shows how DK implements curve creation/editing among others here:http://apptree.net/code/dk/Binaries/DKMiniDemo_app_1.2.zip ...which, by the way, is one hell of an impressive bare bones demo app. DrawKit is fantastic and the fact that it's open source is remarkable, thank you Graham. -- Rob Keniger ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com