GSPathSegment question

is there a reason path segments and nodes are totally separate via the API? I don’t have strong feelings about how this might be implemented, but it seems intuitive that you could call the nodes associated with segment[1…3] (rather than just point location), or at least the last node given there is a lastPoint method available. it would also be nice to have path direction of the path it is on, too. is this too costly for rendering, or something? currently I have to do a lot of abstraction around this just to make a dict of segments with all the other userful data, which is a totally fine workaround, but I guess just out of curiosity I’m wondering what the reasoning for the current separation between segments and nodes is? maybe I’m just doing things in a non-idiomatic way as I start working with segments more… or maybe there’s some hidden method to the rescue?

Because there’s no clear relationship between nodes and segments. If everything is done right, a node typically belongs to two segments. Forcing segments into the object model hierarchy before nodes would complicate a lot of things. And what about a quadratic segment where the on-curves are implicit?

What are you trying to do?

What keeps you from accessing the path’s direction property?

this is a good way of thinking of it (and not incompatible with what I’m imagining); and you’re right that quadratic segments would complicate things, though I’m not suggesting a different object model, just something like a built-in helper function

I’m working on auto obliques, manipulating paths while trying to keep them compatible. judging extremes, managing new nodes and time etc… perhaps I’m overthinking it, or perhaps shall we say under-thinking it, but I do feel something as simple as having segment.lastNode would be helpful for orienting ones self in loops

nothing! any of this can always be solved another way, I’m just thinking about conveniences in certain circumstances. path direction makes less sense, the more I think about it

someone (ahem) should teach a class on having fun with all the segment functions :slight_smile:

I wouldn’t use segments but iterate the nodes directly. The segments can be used for very specific cases e.g. removing overlaps, when the node structure will be different anyway.

that’s what I thought initially until I ran into the extremeTimes() being on segments

There is a function: GSExtremeTimesOfBezier() that is used in extremeTimes() . You can use it like this:

from AppKit import NSBundle, NSPoint
bundle = NSBundle.bundleForClass_(GSFont)
objc.loadBundleFunctions(bundle, globals(), [("GSExtremeTimesOfBezier", b'{CGPoint=dd}{CGPoint=dd}{CGPoint=dd}{CGPoint=dd}{CGPoint=dd}o^do^do^do^d')])
print(GSExtremeTimesOfBezier(NSPoint(10, 10), NSPoint(30, 30), NSPoint(30, 60), NSPoint(10, 90), None, None, None, None))

You need to run objc.loadBundleFunctions only once e.g. in the init code of the plugin.

ahhh I had come across that but didn’t realize what it was doing, I was wrong thinking the python API was the simple way :sweat_smile:

the None values are for quadratic, or something else?
o^do^do^do^d - what is this?

is there a way to look at available objc functions like GSExtremeTimesOfBezier?

Those c-functions return the values by pointer references. Have a look at the definition:

void GSExtremeTimesOfBezier(NSPoint p1, NSPoint p2, NSPoint p3, NSPoint p4, CGFloat *t1, CGFloat *t2, CGFloat *t3, CGFloat *t4);

python doesn’t have pointers so pyobjc returns them in tuple instead but you still need to call it with enough arguments.

You can learn about most of those functions by looking at the core documentation or the headers in `Glyphs 3.app/Contents/Frameworks/GlyphsCore.framework/Versions/A/Headers (e.g. in GSGeometrieHelper.h)

1 Like

What is the CGPoint that GSExtremeTimesOfBezier returns first in the tuple?

I made a mistake with the function signature. It has to be:

b'v{CGPoint=dd}{CGPoint=dd}{CGPoint=dd}{CGPoint=dd}o^do^do^do^d'

The replaces the first CGPoint with “v”. Then it should only return four numbers.