Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Points Of Inflection / Balance / Harmonize #4900

Merged
merged 28 commits into from Feb 21, 2022

Conversation

linusromer
Copy link
Contributor

As intended I have implemented entries in the "Element Menu" named "Add Points Of Inflection", "Balance" and "Harmonize" for the font view, the char view and the metrics view. Corresponding scripting functions are included as well.

  • "Add Points Of Inflection" relies on the computation that is already used to display the points of inflection but then additionally splits the spline there. Hotkey: Ctrl+Shift+Y (homophone Ynflection)
  • "Balance" makes the line between the control points parallel to the chord such that the area is preserved. This is an improved version of the algorithm known as "tunnify". Hotkey: Ctrl+Shift+P (homophone Palance)
  • "Harmonize" moves the smooth on-curve points between its adjacent control points such that the adjacent curvatures become equal (except for sign at points of inflection). Hotkey: Ctrl+Shift+Z (harmoniZe)

The translations to German are included. However, the translations to other languages will have to be done by others.

This makes my plug-in https://github.com/linusromer/curvatura more or less useless (because the "Harmonize handles" of curvature is probably not used by anybody).

Type of change

  • New feature

@ghost
Copy link

ghost commented Feb 1, 2022

Awesome. FTR, Here are binary artifacts for this pull already:

@ctrlcctrlv
Copy link
Member

Fantastic, excellent work. Finally my decision to make MFEK's point type FontForge-similar (with next and prev points) (a, b), as well as having PrevNext trait on Contour impl's is going to be bear some fruit, as many of your algorithms here I can literally copy and paste and run a few sed's on to bring them into MFEK. :-)

Thanks a lot also for using BPAdd and BPCross so often as it really helps me understand how the code works.

@ctrlcctrlv
Copy link
Member

Oh, and by the way, some code review as far as this project goes—

① Why did you add the options to the MetricsView? Seems to clutter menus and not make much sense, can you rationalize it? https://github.com/fontforge/fontforge/pull/4900/files#diff-7dcb402a6783e5b71a16f0e5edf1387845b40574aaeea9faa90c172ee7832c05
② Regarding adding new hotkeys, is this allowable @skef? I think we said it might not be.
③ Please remove the font-level Python API functions. It's my opinion they're unnecessary clutter that can be had the same by iteration, but are very unlikely to lead to pleasing results when applied to whole font. I understand having the functions in the FontView, as it only is applied to selected glyphs, but not in Python API.
④ For the Python docs, please either— ⓐ group your new functions together in each section (layer, contour, &c) with a link to your Curvatura docs on top, (breaking alphabetization is IMO ok, but if we think it's not then) ⓑ make a new docs section for these functions with images and link to that doc before the short blurb of each.
⑤ Also for the Python docs, only write the short blurb once, for the others, write please see contour.whatever. contour is likely to be the most often used API.

@linusromer
Copy link
Contributor Author

@ctrlcctrlv
① Well, that is a actually a question I have asked in this discussion. I reasoned that if "Add Extrema" has an entry in the metrics view then "my" three functions should probably have entries as well. But I will gladly remove them from the metrics view, because for me personally there is no reason for them.
② I think it's a pity when Harmonize and Balance do not get default hotkeys (however, I could live happily without a hotkey for Add Points Of Inflection). There are not many hotkeys I am using for my font designs but Harmonize and Balance are among them (besides Add Extrema, Simplify, Merge, Round, Save, Autohint, Open Metrics View). One reason for doing this pull request was that a new user can use these functions out of the box without adding additional files (like curvatura.py oder a personal hotkeys file).

I will implement your suggestions 1,3,4,5 as soon as I have an answer to your question 2.

@skef
Copy link
Contributor

skef commented Feb 1, 2022

I think there's an argument to be made that Add Points of Inflection should appear everywhere that Add Extrema appears, in contrast with Harmonize and Balance. The former are similar in that they're more about normalization/avoiding potential tool problems than about output geometry. So I would recommend leaving Add Points of Inflection in those places even if/when the other two are removed.

I'm not aware of any guidelines against adding hotkeys to new "core" menu items. User-chosen hotkeys override core hotkeys (I believe), so people using them for something else shouldn't be affected.

@ghost
Copy link

ghost commented Feb 1, 2022

I'm not aware of any guidelines against adding hotkeys to new "core" menu items. User-chosen hotkeys override core hotkeys (I believe), so people using them for something else shouldn't be affected.

JFTR, Is there a way to fully customize FontForge hotkeys?

@skef
Copy link
Contributor

skef commented Feb 1, 2022

@Symbian9 Yes, this should work: https://fontforge.org/docs/ui/misc/HotKeys.html#hotkeys-hotkeyassign

@jtanx jtanx mentioned this pull request Feb 1, 2022
@jtanx jtanx added this to the 2022 q1 milestone Feb 1, 2022
@linusromer
Copy link
Contributor Author

@ctrlcctrlv
After skef's comment I have implemented the following things regarding your five points:
① I have removed Balance and Harmonize from MetricsView but not Add Points Of Inflection.
② My shortcuts are still there.
③ I have removed the font-level Python API functions for Balance and Harmonize but not for Add Points Of Inflection.
④ I have chosen your option ⓐ with .. seealso:: to link to the Curvatura documentation.
⑤ Done.

@skef
Copy link
Contributor

skef commented Feb 3, 2022

I'm gonna wait to review this until #4789 is in and this branch is rebased.

@skef
Copy link
Contributor

skef commented Feb 13, 2022

@linusromer Now that #4789 is merged can you rebase this off the current master. I think there are a bunch of common commits and doing that will make reviewing easier.

@skef
Copy link
Contributor

skef commented Feb 14, 2022

I've started reviewing this and so far the new code looks good, however, when reviewing with all commits it looks like some of #4789 was reverted. Could you take a look and either figure out how I or github is confused or fix the issue?

@linusromer
Copy link
Contributor Author

@skef Github is confused because of me. I think I have somehow messed up the commits of my "master" and "inflections" branches. But now I think I have solved the issue by cherry-picking the corresponding commits of my master branch. (In retrospective I probably should have done a rebase first to make things clearer.)
I have tested everything again and looked at the "files changed" and now I am quite sure that nothing from #4789 is reverted.

@@ -929,6 +929,108 @@ void FVAddExtrema(FontViewBase *fv, int force_adding ) {
ff_progress_end_indicator();
}

void FVAddInflections(FontViewBase *fv, int anysel) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I diffed these and they're identical except for the (reused) strings and the function call. The code base has that sort of thing but in this case I think its worth adding the string and function pointer to the signature of one of these and having the others be one-liners.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your suggested generalized solution is surely preferable. I will implement it as soon as I have a little bit more time. This affects FVHarmonize and FVBalance as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@skef I am a little stuck here. I have tried your suggestion with a generalized function
void _FVElementAction(FontViewBase *fv, int anysel, void (*func)(SplineChar*, SplineSet*, enum ae_type, int), const char* progressmsg) that calls func(sc, sc->layers[layer].splines, anysel, emsize). However my three functions SplineCharAddInflections(), SplineCharBalance() and SplineCharHarmonize() only take 3 parameters, whereas SplineCharAddExtrema() takes one additional parameter emsize. I think there is no elegant solution of optional parameters in C. There is of course a cheap solution: void _FVElementAction(FontViewBase *fv, int anysel, const char* functionname) that contains a switch (functionname). Is there something I am obviously missing?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was just looking at the three added functions. Don't worry about the more ambitious project of including SplineCharAddExtrema().What makes these worth doing is the identical signature of the inner function.

Copy link
Contributor

@skef skef left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given the lack of refigures I'm wondering how extensively this PR was tested in the UI vs just confirming the math works.

@@ -3468,6 +3468,51 @@ return( NULL );
Py_RETURN( self );
}

static PyObject *PyFFContour_AddInflections(PyFF_Contour *self) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same with these.

@@ -4424,6 +4475,51 @@ return( NULL );
Py_RETURN( self );
}

static PyObject *PyFFLayer_AddInflections(PyFF_Layer *self) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And these

@@ -9395,6 +9497,30 @@ return( NULL );
Py_RETURN( self );
}

static PyObject *PyFFGlyph_AddInflections(PyFF_Glyph *self) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are short so ambivalent here.


/* Make the line between the control points parallel to the chord */
/* such that the area is preserved (kind of an improved "tunnify") */
Spline *SplineBalance(Spline *s) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're (obviously -- this is the point) modifying SplinePoint values in this function but I don't see calls to SplineRefigure() anywhere in the path. (Above that's taken care of by SplineSplit().)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, SplineRefigure() is not called ( I just have checked it) although it probably should be called. I HAVE tested my PR and I did not run into problems so far. But my tests were not more systematic than testing some problematic cases and run the functions on some huge fonts. I did not implement a separate torture test for the UI functions. Is there an existing torture test that I have missed (like trip and trap by Donald E. Knuth)?
Anyway, I will add SplineRefigure() calls as soon as I have a little bit more time.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is absolutely no good systematic method of UI testing, unfortunately. When one is adding or making significant modifications to UI-tied functionality it's best to just play around with it in the UI to see what happens. Making real-time changes in a CharView is probably the best way as its most likely to turn up updating problems (such as those caused by a lack of SplineRefigure().


/* Make the splines adjacent to the SplinePoint sp G2-continuous */
/* by moving sp between its adjacent control points */
void SplinePointHarmonize(SplinePoint *sp) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, no SplineRefigure()s to be seen.

…functions, added SplineRefigure() to the base functions of Balance and Harmonize
@linusromer
Copy link
Contributor Author

@skef I have abstracted all occuring AddInflections, Balance, Harmonize in python.c and in the FontView and CharView (the python font method for AddInflections excluded). And I have added SplineRefigure() as desired. My tests for this change were not very deep. I will test it more in short time.

@lgtm-com
Copy link

lgtm-com bot commented Feb 19, 2022

This pull request introduces 9 alerts when merging 9b9f21b into dca27e2 - view on LGTM.com

new alerts:

  • 9 for Missing return statement

@linusromer
Copy link
Contributor Author

@skef After implementing the asked changes I have now tested it more extensively (all Python functions, FontView, CharView, MetricsView) with different fonts (also with quadratic layers). I think it should work now.

Copy link

@iterumllc iterumllc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me!


#, c-format
msgid "Include filename too long on line %d of %s"
msgstr "Include-Dateiname zu lang in Zeile %d in %s"
msgstr "Name der einzufügenden Datei zu lang in Zeile %d in %s"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This actually needs to be updated in crowdin, I'll find a way of getting it there

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll fix this once merged

fontforge/fontviewbase.c Outdated Show resolved Hide resolved
@jtanx jtanx merged commit 6d63889 into fontforge:master Feb 21, 2022
@linusromer linusromer deleted the inflections branch February 22, 2022 17:49
@linusromer
Copy link
Contributor Author

linusromer commented Apr 10, 2023 via email

@Typedesigners
Copy link

Typedesigners commented Apr 10, 2023

@linusromer In FontLab, the tunni lines are given numbers. For example, for an arc shape 60 or 50. This allows you to determine how much an arc is curved. Whether it is flatter or rounder. This way you can create exactly the same round shapes for all letters. At the moment, FontForge does not have an exact way to easily control how much an arc is curved.

https://help.fontlab.com/fontlab-vi/Tunni-Lines/

@Typedesigners
Copy link

@linusromer Smart Corners - It might be possible to implement a similar function in FontForge.
https://help.fontlab.com/fontlab-vi/Using-Smart-Corners/

@linusromer
Copy link
Contributor Author

linusromer commented Apr 10, 2023 via email

@Typedesigners
Copy link

@linusromer Maybe as a plugin?
It would also be nice to have a function in FontForge that allows you to centre elements horizontally and vertically. Such alignment functions are a matter of course in any graphics programme such as Illustrator or Affinity Designer.

@linusromer
Copy link
Contributor Author

linusromer commented Apr 18, 2023 via email

@Typedesigners
Copy link

I am a type designer, not a programmer, so I cannot program a plug-in.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants