NSBezierPath (Modifying Paths)

2009-02-04 Thread Joseph Crawford

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)

2009-02-04 Thread Quincey Morris

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)

2009-02-04 Thread Joseph Crawford

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)

2009-02-04 Thread Quincey Morris

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)

2009-02-04 Thread Graham Cox
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)

2009-02-04 Thread Rob Keniger


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