FOG vs. FL - lost tangent points

peterbruhn's picture

I'm slowly trying to come to terms with Fontlab, even though it's not a intinutive GUI.

I still do most of my work in Fog and only use Fontlab for the last bits. However,
when opening my files in Fontlab, some of my tangent points
are gone and replaced. (see image below)

Tangent Points
Why is that? Is it just a preference that I missed?
Or doesn't Fontlab handle tangent points? How will I then be able to make smooth transitions?
Anyone out there with FL wisdom?

kentlew's picture

Peter --

I'm going to guess that what is happening is the translation from FOG to Postscript to FL. Postscript doesn't make a distinction about point types, coding only the coordinates of the on-curve points and the associated control points. If I'm not mistaken, PS doesn't handle decimal places, so coordinates are rounded to the nearest integer when a PS font is generated. Non-orthogonal curves and tangents are particularly susceptible to this.

When FL reads the PS data from the font, I'm guessing that if the points aren't exactly colinear (due to rounding) that FL will not interpret them as tangent points per se. I would presume that your points and controls are still in the proper places (allowing for rounding). I'd be curious to see a screenshot with the control handles showing. For instance, did FL add a handle to the bottom side of that lower, outside curve point?

I'm just starting the arduous transition to FL myself and am by no means an expert. Someone more technically savvy, like John Hudson, might have a better explanation.

-- Kent.

peterbruhn's picture

Hi Kent,
I know I read somewhere about different types of round points in FL.
I thought I read it here at Typophile but I can't find it.
But even if that's the case, I would
like to know which curve points are tangent like points by just looking.

Here's a closer example (Fog version to the left).tangent2
Sorry about the large image, but otherwise it's hard to see.
/p

kentlew's picture

Peter --

I've been thinking about this and spending some time with the FontLab manual.
I had an insight that I think might help.

The FOG model is point-based. But the FontLab model is segment-based.

What I mean is that in FOG you are usually focused on what kind of point
you're placing. Whereas in FL, the emphasis is on what kind of line segment
is being operated on. FOG has three kinds of points -- corner, curve, and
tangent. FL doesn't make these distinctions.

FL distinguishes between two different kinds of line segment -- a straight line
(which they also call a vector) and a curve (a bezier curve). A curve is described
by four points -- two end points on the curve (nodes) and the two bezier
control points on the handles. A straight line is controlled by only two nodes --
one at either end, with no control handles.

FL also distinguishes two different kinds of transitions between line segments --
a node can either be a smooth connection or a sharp connection.

So, if you have a curve meeting another curve, then the node will have two
control handles, one contributing to each of the two curves. If the connection
is smooth, then the two handles will be co-linear -- that is, they are linked
and stay aligned with each other -- so this kind of node is what FOG would call
a curve point.

If two curves meet and the connection is sharp, then the two control handles
can be moved independent from one another. This node would then constitute
a corner point in FOG.

If two straight line segments meet, then the node does not have any control
handles and is necessarily sharp. This would also be considered a corner point
in FOG.

If a straight line meets a curve, then the node will have one control handle on
the curve side. If the connection is sharp, then this control handle can move
any which way and the node would be considered a corner point in FOG.

But if the connection is smooth, then the control handle on the curve side
will be co-linear with the vector segment meeting up with the curve and will
only move in a line with this vector -- and this is what FOG would call
a tangent point.

Does this help?

So, you need to notice whether the node between a straight line and a curve
is smooth or sharp. When it is selected, you will see off to the side of the
node either a circle (smooth connection) or an x (sharp connection). You can
also turn on all connection types for every node, whether selected or not, by
selecting the button from the View/Show Layers toolbar.

So, for example, if you select the node on the top of the inside of your
counter, you will see whether it is a smooth connection or not. If it isn't,
then double click the node to toggle the connection style. When the connection
is smooth, then you can change the "curve" on the right side to a straight line
by selecting the right control handle of the node and deleting it. (Deleting
either control handle of a segment will convert it to a straight line vector, since
a curve needs to be defined by two control handles.)

Once the right-hand segment is a straight line and the left-hand segment is a
curve and the node is a smooth connection, then the handle on the left will
only move in line with the straight segment and you will have, in effect, a
tangent point.

I hope this makes sense and is helpful.

-- Kent.

alan's picture

To follow up on Kent's thorough description, I wanted to add that FL has an excellent way of keeping users on their toes with regard to what is allowed in the world of PostScript Type 1 fonts:

FL doesn't let you form a curve by anything other than two points with control handles. In Fontographer, you're allowed to create a curve that has a BCP handle on one end, and an "empty" point on the other end. But this can produce errors, since it is effectively creating a point-on-top-of-point situation. FL shows you that this is happening by immediately introducing a complimentary BCP handle when you create a curved segment. It invites you to define the curve properly.

FL also makes you aware of the nature of Type 1 curves, by making the "closepath" and start/end points a tangible part of the path. This can be disorienting at first, and seem like a hassle, but it reveals the nature of the curves and allows greater control.

Lastly, if you turn on the "connection type" layer as Kent suggests, FL does another neat thing: when two consecutive BCP handles cross each other's paths, the connection type indicator flips to the opposite side of the point, notifying you that the curve is not constructed as well as it could be.

Lastly lastly, setting the preferences to show points in color is another handy visual cue.

peterbruhn's picture

Thank you Kent (and Alan) for the thorough explanation, I finally got it sorted out.
I realise that I will have to learn a whole new concept on how to work on my faces...sigh.
Or hoping for a more Fog-like interface in the upcoming versions. I guess it will have to be a gradual transition

hrant's picture

> In Fontographer, you're allowed to create a curve that has a BCP handle on one end, and an "empty" point on the other end.

And this is "illegal"? Are you sure?
What a bummer. I use that structure all the time, mostly because it's much more elegant: less redundant data -> more control.

On the other hand, I have noticed that strange things happen when such structures are output as a TT font from Fog, for some reason.

hhp

alan's picture

Yes, Hrant. To the best of my knowledge, that is considered a Type 1 no-no. It's my understanding that BCPs are considered points, along with vertices. When you create a one-sided curve, you are invisibly creating a BCP on the opposite end of the curve. That invisible BCP (invisible in Fog, at least) is located directly on top of the vertex, so then you have a point-on-point situation. Whether or not this is as likely to cause spiking as two vertices on top of each other, I'm not sure. But it's worth staying away from it (yeah, it's annoying, I agree).

Alan

Mark Simonson's picture

Alan, could you post an illustration? I'm having trouble visualizing the situation you describe.

kentlew's picture

Alan, Hrant --

I'm not a real Postscript jockey, but to the best of my
understanding I'm not so sure that the one-bcp-handled
curve is necessarily "illegal." The thing is that the
various Postscript curveto commands require a
set number of arguments, based on the assumption of
two handles and endpoints (actually, the first point is a
given, so generally only six arguments are required.
You can reference the T1 Font Format, Ch. 6, pg 52.)

The thing about FL is that it constructs curves with the
same assumption. But if you create a single-handled
curve in FOG, all that means is that the generated PS
instruction will contain a few arguments whose values
are zero. There's no restriction or caution about these
arguments being non-zero, as far as I can tell.

I think that since these arguments only seem to be
calculation values, this construction wouldn't constitute
any point-on-point sort of violation. But who knows
what happens when Hrant tries to convert to TT.

But Hrant, you don't gain any worthwhile savings in
terms of data points in the actual PS-generated font.
Maybe a digit here or there, but who's counting? Again,
I don't know about TT.

-- K.

hrant's picture

> you don't gain any worthwhile savings

I didn't mean in the actual font data, but in the user's head: when you're making/adjusting a curve, there's less to handle (at least up to a point).

hhp

alan's picture

Mark - I've attached a series of images demonstrating the issue with the BCPs. The first image is how you might construct a curve in Fog (the point with the red circle is "empty"). The second image is how this exact outline opens in FL 4.5. The yellow dot you see in the middle of that point is a BCP that is lying directly on top of its vertex. (This is how FL translates the "empty" point when the other side has a BCP.) The third image is ideally how it should be constructed.

However, if what Kent says is correct, then this is all a moot point. But this is just how I've learned it.

Alan

hrant's picture

Even if it's actually legal, I guess it's still probably better to avoid "empty" curve-recieving points, at least in the final result. Hmmm, Python script, anyone?

A similar thing (legal but ill-advised) is to leave off explicit inflection points (like in the spines of an "s"), although this is actually commonly done by some otherwise fine designers (if rarely in very obvious spots such as the "s" spines). One good reason to define all your inflection points explicitly is TT output/conversion - it consistently blows up, at least in Fog. But I think there are other reasons too. Fortunately, you can easily spot a missing inflection point: the BCPs will be on opposite sides of the curve.

hhp

alan's picture

> Fortunately, you can easily spot a missing inflection point: the BCPs will be on opposite sides of the curve.

FL 4.5 used to be able to point them out with the FontAudit layer turned on. But it doesn't work for me any more. Any idea why? (It also won't let me turn *off* checking for semi-horizontal and vertical vectors, even though it's unchecked in the prefs.)

Alan

kentlew's picture

Alan --

I've been noticing the exact same problem with font
audit. I appreciate the feature, but I wish turning off
the semi-horizontal and semi-vertical vector alert really
worked. Very annoying.

From your diagram above, the Postscript instruction for
the first would end up something like

0 0 -66 -81 -103 0 rrcurveto *

(Note: I'm assuming this is the bottom curve of a
counter and thus the direction is clockwise. I don't
know your actual coordinates, so this is just an
approximation based on the pixel dimensions of your
screenshot.)

The instruction for the second would be more like

-33 -37 -60 -44 -76 0 rrcurveto

I don't really follow the *math* for applying the Bezier
equation, so I don't know if those initial zeros in the
first instruction would pose any potential weirdness.
I do know that trying to geometrically construct a
single-handled bezier is a little odd.

For whatever it's worth.

-- K.

* I suppose, technically, this first instruction could even
be written as 0 -66 -81 -103 vhcurveto, but I bet
that would really lead to interpretive weirdness.

John Hudson's picture

Even if it's actually legal, I guess it's still probably better to avoid "empty" curve-recieving points, at least in the final result.

Not least because this is illegal in a TrueType font, so if your outline is going to be the source for any TT format conversion such constructions should be avoided. The MS Font Validator will report such constructions as outline errors.

yar's picture

FontLab will convert "single-handed" cubic curve into correct TT curve using the alternative curve conversion algorithm. There was a problem with version 4.0.x and maybe early releases of the 4.5, but now it works fine.

There is no trouble to render single-handed curve to series of short straight lines (as most rasterizes do before filling the outline), so I don't think PostScript or ATM will have any problems rendering these curves.

Theoretically single-handed curves may cause a problem during conversion to the quadratics when this case is not separately handled, which means that I'd recommend to avoid this type of curves where possible.

I think some algorithm may be developed which will convert single-handed curves to normal ones using some form of approximation. It might be a good example of nice Python programming in FontLab :-)

hrant's picture

> I think some algorithm may be developed which will convert single-handed curves to normal ones

But above that you wrote: "FontLab will convert 'single-handed' cubic curve into correct TT curve" so don't you have the algorithm already?

BTW, a possibly related question:
I'm curious, where did you get the factor of 0.55197 when making a "perfect" circle?

hhp

yar's picture

>But above that you wrote: "FontLab will convert 'single-handed' cubic curve into correct TT curve" so don't you have the algorithm already?

Well, you can convert single-handed curve to quadratic curve and back, but as a result you will get 2 cubic curves. I mean that I can imagine algorithm which will convert single-handed curve to one "normal" curve. Alan Dague-Greene provided good example of what I mean.

>I'm curious, where did you get the factor of 0.55197 when making a "perfect" circle?

Did we publish this number somewhere or you just draw a very big circle in FL? :-)

Actually I don't remember how it was calcualted in the early days of FL, but now I would do it this way (pardon my math): measure a distance (along x or y direction) from the point located at 45 degrees on a curve and a midlle point of the one-quarter curve. On a curve it is: R * (4 + 3 * X) / 8 [where X is a value we want to find], on a circle: R / sqrt(2).

Finally our X is [in C math notation]: (8 / sqrt(2) - 4) / 3

Precise value is: 0.55228474983079339840225, which is quite close to the value we use in FL (and which history I don't remember).

hrant's picture

> 0.55197

I saw it in some Python scripts that come with FL.

> now I would do it this way ....

Nice.

hhp

kentlew's picture

Hmmm, I really want to follow this bit, but I'm not sure
what factor (= 0.55197) you're referring to, Hrant. So I
don't quite follow Yuri's explanation. Could you back up
a step and let me in on what you're calculating here?
Thanks.

-- K.

yar's picture

There is no way to draw a precise circle with the cubic Bezier curve, but it is possible to approximate it. You can draw a 1/4 of a circle (90 degrees) with a single curve with a minimal error: to do that you need to set a length of each BCP to that magical factor multiplied to circle radius. As an experiment you can draw a circle in FL (it will produce 4 curves) and measure the length of each curve's BCP. Then take a calculator and divide it to half of the curve's diameter.

Btw, it looks that calcualtion in my previous message may not give the best approximation. It will place the middle point of the curve exactly on the circle, but total approximation error may not be minimal. To calculate the ideal "factor" you need to render a curve and then approximate it with the curve minimizing the total error. As I understand it is how we got the original value.

hrant's picture

Well, it's probably not really related to the main issue. But here's an explanation: if you draw a "perfect" circle (using the application's tool, or maybe a physical one and then trace it), and you measure the length of the BCP arms in each quadrant, they are about 0.552 of the whole length. This is the value required in cubic bezier math to get a "perfect" circle. BTW, "perfect" is in quotes because you really can't represent a true circle in beziers (of any order).

The way this might be related to the main issue is this: if you were to convert a one-sided curve to a near-equivalent two-sided one, some sort of preset factor values might be the trick.

hhp

kentlew's picture

Okay, thanks; I thought that might be what you guys were talking about.

(I still don't quite understand how you derived your formula, but that's okay.)

-- K.

paul's picture

Hi,

I know that this is an old, dead thread, but I have an observation about tangent curves.

As far as I know, FreeHand and Fontographer (both developed by Alstys) were the only PostScript drawing programs that have ever supported tangent curves

Syndicate content Syndicate content