• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..03-May-2022-

java/H05-May-2020-978761

m4/H05-May-2020-7572

tests/H03-May-2022-1,6071,313

.gitignoreH A D05-May-2020158 2217

AUTHORSH A D05-May-2020367 2017

COPYINGH A D05-May-202034.3 KiB675553

ChangeLogH A D05-May-20204.5 KiB9481

INSTALLH A D05-May-202015.2 KiB366284

Makefile.amH A D03-May-20221.8 KiB5438

READMEH A D05-May-20202.2 KiB6953

README-GeorgeWilliamsH A D05-May-2020471 1511

README-RaphLevienH A D05-May-20203.3 KiB11383

README.mdH A D05-May-202015.1 KiB379287

bezctx.cH A D05-May-20201.7 KiB6942

bezctx.hH A D05-May-20201 KiB3118

bezctx.mdH A D05-May-20209.3 KiB338284

bezctx_intf.hH A D05-May-2020536 3323

config.guessH A D05-May-202047.4 KiB1,6751,462

config.subH A D05-May-202030.9 KiB1,7941,637

configure.acH A D05-May-202011.1 KiB317278

fontforge.shH A D05-May-202095 31

get-spiro-src.shH A D05-May-2020166 42

libspiro.3H A D05-May-20201.4 KiB5346

libspiro.pc.inH A D05-May-2020378 1411

spiro.cH A D05-May-202040.9 KiB1,3591,185

spiro.hH A D05-May-20201.4 KiB5840

spiroentrypoints.cH A D05-May-20203 KiB9360

spiroentrypoints.hH A D05-May-20203 KiB7740

README

1LibSpiro is a shared library designed to give programs the ability to create
2smooth continuous curves based on a given set of codes and X,Y constraints.
3
4The main user(s) of Libspiro are Font editing programs such as FontForge,
5and forked copies have been seen in more artistic programs such as InkScape,
6or in libraries such as GEGL. There may be other possible uses in future,
7and this library has strong potential in graphical and vector type programs.
8
9Developers interested in also sharing and making use of LibSpiro will likely
10want to read (these README files too to understand LibSpiro better):
11README-RaphLevien
12README-GeorgeWilliams
13
14There is a large amount of information and math on RaphLevien's website for
15developers interested in how LibSpiro works.
16
17Developers interested in example programs, can take a look at spiro.c found
18within FontForge, InkScape, GEGL and call-test.c included with this library.
19
20Installation
21============
22
23Installing from Git master requires 2 preparatory steps:
24
25First, you need to create the `configure' script if you do not have it yet.
26This will require autoreconf and automake to build `configure'.
27> autoreconf -i
28> automake --foreign -Wall
29
30
31Second, you then use the usual steps to compile it.
32Various operating systems and setups will need `configure' options set.
33The INSTALLATION file has detailed info for `configure' options.
34Example install steps for Linux, FreeBSD, Win32/64 are shown below:
35
36Installing on Linux
37> ./configure
38> make
39> make check
40> sudo make install
41
42Installing on FreeBSD10 (using clang3.3 or 3.6)
43> ./configure --prefix=$(pwd)/BUILD
44> make clean
45> make
46> make install
47
48Installing on Windows 32-bit
49> ./configure --host=i686-w64-mingw32 --prefix=$(pwd)/build-w32
50> make clean
51> make
52> make install
53
54Installing on Windows 64-bit
55> ./configure --host=x86_64-w64-mingw32 --prefix=$(pwd)/build-w64
56> make clean
57> make
58> make install
59
60NOTE: Some Distros and Operating Systems may require you to run 'ldconfig'
61to recognize LibSpiro if you are not rebooting your computer first before
62installing another program that depends on LibSpiro. To do this, you may
63need to run 'ldconfig' in 'su -' mode after you have done 'make install':
64
65	$ su -
66	# ldconfig
67	# exit
68	$
69

README-GeorgeWilliams

1This is a shared library designed to give FontForge (and others) access to
2Raph Levien's spiro splines.
3
4You may (possibly) be able to obtain more recent versions of Spiro from
5    http://levien.com/garden/ppedit/
6use the get-spiro-src.sh script to do so.
7
8To build, type
9    ./configure
10    make
11    make install
12
13Currently I extract very little from spiro, just the bare minimum to convert
14a series of (marked) points to a set of cubic bezier curves which ff can use.
15

README-RaphLevien

1README for ppedit
2
3Raph Levien
44 May 2007
5
6ppedit is my prototype application for editing curves using my
7curvature-continuous spirals. While I have used this code to draw many
8font outlines, it is very rough around the edges, and is far from a
9polished tool.
10
11
12== License and patent grant ==
13
14All code in this package is released under the terms of the GNU GPL,
15version 2 or later, at your choice.
16
17Further, there is a provisional patent application filed for the
18underlying curve technology. The following patent grant applies to any
19patent which may be issued as a result of that application:
20
21Whereas, Raph Levien (hereinafter "Inventor") has obtained patent
22protection for related technology (hereinafter "Patented Technology"),
23Inventor wishes to aid the the GNU free software project in achieving
24its goals, and Inventor also wishes to increase public awareness of
25Patented Technology, Inventor hereby grants a fully paid up,
26nonexclusive, irrevocable, royalty free license to practice the
27patents listed below ("the Patents") if and only if practiced in
28conjunction with software distributed under the terms of any version
29of the GNU General Public License as published by the Free Software
30Foundation, 59 Temple Place, Suite 330, Boston, MA 02111. Inventor
31reserves all other rights, including without limitation, licensing for
32software not distributed under the GNU General Public License.
33
34== Building ==
35
36The main build supported right now is the Gtk2/cairo one. There's also
37a Mac build and a Gtk1 one, but those aren't guaranteed to work.
38
391. Make sure you've got ../x3/ in a directory parallel to ppedit. If
40   you've unpacked from a tarball, this should be the case already.
41   From darcs, use: darcs get http://levien.com/garden/x3
42
432. make
44
453. The binary is ppedit
46
47== Using ==
48
49The numeric keys 1-6 select the mode. 1 is selection, 2-6 select
50different point modes:
51
522: Add G4-continuous curve point
533: Add corner point
544: Add left-facing one-way point
555: Add right-facing one-way point
566: Add G2-continuous curve point
57
58Note: Dave Crossland has a set of alternate keybindings which are
59probably faster.
60
61== Plate files ==
62
63Ctrl-S saves a plate file in a file of the name 'plate'. Additionally,
64a plate file can be given as a command line argument. The file uses
65simple S-expressions, with a one-character code for each point, then
66the X and Y coordinates - 0,0 is top left.
67
68Here's the cap U from Inconsolata, for example:
69
70(plate
71  (v 68 78)
72  (v 159 78)
73  (o 158 92)
74  ([ 148 115)
75  (] 148 552)
76  (o 298 744)
77  ([ 459 549)
78  (v 459 78)
79  (v 536 78)
80  (] 536 547)
81  (o 295 813)
82  ([ 68 551)
83  (z)
84)
85
86v: corner
87o: g4
88c: g2
89[: left-facing one-way
90]: right-facing one-way
91
92== Conversion to PostScript ==
93
94Ctrl-P converts to PostScript, saving '/tmp/foo.ps'. Other utilities
95can convert that representation into FontForge, and also optimize the
96Beziers.
97
98== Stability ==
99
100The spline solver in this release is _not_ numerically robust. When
101you start drawing random points, you'll quickly run into divergence.
102However, "sensible" plates based on real fonts usually converge. Some
103tips:
104
1051. Huge changes of angle are likely to diverge.
106
1072. For the first two or three points, G4 points are likelier to
108   converge than G2's. For longer segments, G2 is more likely.
109
1103. Start on a curve point.
111
112A more numerically robust approach is in the works.
113

README.md

1# Spiro ![](spiral32.png) [![Coverity Scan Build Status](https://scan.coverity.com/projects/794/badge.svg?flat=1)](https://scan.coverity.com/projects/794)
2
3## Introduction
4
5![](spiro-a.png)
6
7Spiro is the creation of [Raph Levien](http://www.levien.com/). It simplifies the drawing of beautiful curves.
8
9Using bézier splines an artist can easily draw curves with the same slope on either side of an on-curve point. Spiros, on the other hand, are based on clothoid splines which make it easy to maintain constant curvature as well as constant slope. Such curves will simply look nicer.
10
11Raph Levien's spiro splines only use on-curve points and so are easier to use and more intuitive to the artist.
12
13This library will take an array of spiro control points and convert them into a series of bézier splines which can then be used in the myriad of ways the world has come to use béziers.
14
15## Installation
16
17Installing from Git master requires 2 preparatory steps:
18
19First, you need to create the ./configure script if you do not have it yet
20```sh
21autoreconf -i  (or use 'autoreconf --install --force' for more modern setups)
22automake --foreign -Wall
23```
24
25Second, you then use the usual steps to compile the library.
26Various operating systems and setups will need ./configure options set.
27The INSTALLATION file has detailed info for `configure' options.
28Example install steps for Linux, FreeBSD, Win32/64 are shown below:
29
30Installing on Linux
31```sh
32./configure
33make
34make check
35sudo make install
36```
37
38Installing on FreeBSD
39```sh
40./configure --prefix=$(pwd)/BUILD
41make clean
42make
43make install
44```
45
46Installing on Windows 32-bit
47```sh
48./configure --host=i686-w64-mingw32 --prefix=$(pwd)/build-w32
49make clean
50make
51make install
52```
53
54Installing on Windows 64-bit
55```sh
56./configure --host=x86_64-w64-mingw32 --prefix=$(pwd)/build-w64
57make clean
58make
59make install
60```
61
62NOTE: Some Distros and Operating Systems may require you to run 'ldconfig'
63to recognize LibSpiro if you are not rebooting your computer first before
64installing another program that depends on LibSpiro. To do this, you may
65need to run 'ldconfig' in 'su -' mode after you have done 'make install':
66```sh
67	$ su -
68	# ldconfig
69	# exit
70	$
71```
72
73## Usage
74
75### In FontForge
76
77FontForge will autodetect libspiro when it is installed in the usual way.
78
79An exception to this is with the Mac bundled version (where `FontForge.app` is copied to `/Applications`). To install your compiled version into the bundle, run ```sh ./configure --prefix=/Applications/FontForge.app/Contents/Resources/opt/local/ ```
80
81#### Crash Reporting
82
83Mac OS X: A helping script, `./fontforge.sh` is provided to run FontForge inside a debugger to get useful information on solving crashes. An example issue is at https://github.com/fontforge/libspiro/issues/4
84
85# Developing
86
87### Two methods of using libspiro in your programs
88
89- [C](#programming-with-libspiro-in-c)
90- [Java](#programming-with-libspiro-in-java)
91
92### Programming with libspiro in C
93
94- Basic Types
95  - [spiro control point](#the-spiro-control-point)
96  - [ncq control value](#the-ncq-control-value)
97  - [bézier context](#the-bezier-context)
98- [Header file](#calling-into-libspiro)
99- Entry points
100  - int [SpiroCPsToBezier2](#spirocpstobezier2)(spiro_cp *,int n,int ncq,int is_closed,bezctx *)
101  - int [TaggedSpiroCPsToBezier2](#taggedspirocpstobezier2)(spiro_cp *,int ncq,bezctx *)
102
103#### Basic Types
104
105#### The spiro control point
106
107```c
108typedef struct {
109    double x;
110    double y;
111    char ty;
112} spiro_cp;
113
114    /* Possible values of the "ty" field. */
115#define SPIRO_CORNER	'v'
116#define SPIRO_G4	'o'
117#define SPIRO_G2	'c'
118#define SPIRO_LEFT	'['
119#define SPIRO_RIGHT	']'
120#define SPIRO_ANCHOR	'a'
121#define SPIRO_HANDLE	'h'
122
123    /* For a closed contour add an extra cp with a ty set to */
124#define SPIRO_END		'z'
125    /* For an open contour the first cp must have a ty set to*/
126#define SPIRO_OPEN_CONTOUR	'{'
127    /* For an open contour the last cp must have a ty set to */
128#define SPIRO_END_OPEN_CONTOUR	'}'
129```
130
131A spiro control point contains a location and a point type. There are six basic types of spiro control points:
132
133- A corner point – where the slopes and curvatures of the incoming and outgoing splines are unconstrained
134- A G4 curve point – Continuous up to the fourth derivative
135- A G2 curve point – Continuous up to the second derivative.
136- A left constraint point – Used to connect a curve to a straight line
137- A right constraint point – Used to connect a straight line to a curve.
138  If you have a contour which is drawn clockwise, and you have a straight segment at the top, then the left point of that straight segment should be a left constraint, and the right point should be a right constraint.
139- An anchor - Is a knot point with a fixed angle (followed by the handle cp which creates the angle).
140  The anchor behaves as both left and right constraint points at one single point.
141
142The left constraint, right constraint, anchor and handle points are easiest explained using
143examples from path5 and path6 which are tested in tests/call-test5.c and tests/call-test6.c
144
145![](path5.png) ![](path6.png)
146```c
147path5[]		path6[]
148{  0,   0,'{'},	{  0,   0,'{'},
149{100, 100,'c'},	{100, 100,'c'},
150{200, 200,'['},	{200, 200,'a'},
151{300, 200,']'},	{300, 200,'h'},
152{400, 150,'c'},	{300, 150,'c'},
153{300, 100,'['},	{200, 100,'a'},
154{200, 100,']'},	{150, 100,'h'},
155{150,  50,'c'},	{150,  50,'c'},
156{100,   0,'['},	{100,   0,'a'},
157{  0,-100,']'},	{  0,-100,'h'},
158{-50,-200,'c'},	{ 50,-100,'c'},
159{-80,-250,'}'},	{ 20,-150,'}'},
160```
161
162
163## The ncq control value
164
165There is a need to pass additional information to libspiro, and therefore the 'ncq' value was added.
166'ncq' can be thought of as toggle switches telling libspiro how to work with the source spiro control points.
167Below is the current toggle switch definitions, and default 'ncq' value is zero.
168
169```c
170/* int ncq flags and values */
171#define SPIRO_INCLUDE_LAST_KNOT	0x0100
172#define SPIRO_RETRO_VER1	0x0400
173#define SPIRO_REVERSE_SRC	0x0800
174#define SPIRO_ARC_CUB_QUAD_CLR	0x7FFF
175#define SPIRO_ARC_CUB_QUAD_MASK	0x7000
176#define SPIRO_CUBIC_TO_BEZIER	0x0000
177#define SPIRO_CUBIC_MIN_MAYBE	0x1000
178#define SPIRO_ARC_MAYBE		0x2000
179#define SPIRO_ARC_MIN_MAYBE	0x3000
180#define SPIRO_QUAD0_TO_BEZIER	0x4000
181```
182
183The definitions for ncq (above) are:
184
185SPIRO_INCLUDE_LAST_KNOT:
186Existing libspiro behaviour is to add a knot point to match each spiro point, but does not include the last knot.
187This option includes the last knot with the existing output results while the spiro is still open. Closed spiros should refer to the first knot point since the last and first knot are the same.
188
189SPIRO_RETRO_VER1:
190This newer version of libspiro has modified the way path calculations are made.
191The reason for this was seen as an advantage, because it allows a user to scale and move spiro paths, which is a common expectation in graphics, and there are other added advantages, such as making the path as part of templates, and more.
192An effort was made to keep results as close to original as possible, but this was not possible due to scaling factors in the calculations.
193As the main user for libspiro is FontForge, users such as font designers may see the least change since scaling targets x={0..1000}, y={0..1000}, while other users in graphics may see changes since they can be using scales much larger than 1000.
194The good news here is 'SPIRO_RETRO_VER1' allows the user to toggle libspiro to use the older calculation method if the user needs backwards compatibility, otherwise, leaving this off allows spiros to use the new calculation method which allows scaling and moving spiro paths.
195Older programs that use the older libspiro interfaces will see no-change since they use the older calculation method to maintain backwards compatibility.
196
197SPIRO_REVERSE_SRC:
198There may be a need to reverse the spiro path direction.
199This option edits the source spiro path, and reverses the information, then proceeds to continue doing libspiro calculations with the reversed path.
200When libspiro is done calculating bezier output, you will also have a reversed (input) spiro path, therefore save the new spiro path if you need it.
201This simplifies this process for the calling program to a simple option 'SPIRO_REVERSE_SRC', and the results are up to date as per ths version of libspiro.
202NOTE - libspiro calculations are a one-way calculation, so you are not likely to see the same results in the reverse spiro path direction, but if you need this option, it is available here.
203
204SPIRO_CUBIC_TO_BEZIER:
205LibSpiro default action is to create cubic bezier curves.
206
207SPIRO_CUBIC_MIN_MAYBE:
208Cubic arcs can potentially be made with greater bends and less points.
209
210SPIRO_ARC_MAYBE and SPIRO_ARC_MIN_MAYBE:
211Instead of the default cubic output, this exposes the midpoint, which might be useful to someone.
212
213SPIRO_QUAD0_TO_BEZIER:
214Rough approximation of quadratic to bezier curves. Knot points will have smooth connection but midpoints may be visually okay or not.
215
216
217#### The bezier context
218
219```c
220struct _bezctx {
221    /* Called by spiro to start a contour */
222    void (*moveto)(bezctx *bc, double x, double y, int is_open);
223
224    /* Called by spiro to move from the last point to the next one on a straight line */
225    void (*lineto)(bezctx *bc, double x, double y);
226
227    /* Called by spiro to move from the last point to the next along a quadratic bézier spline */
228    /* (x1,y1) is the quadratic bézier control point and (x2,y2) will be the new end point */
229    void (*quadto)(bezctx *bc, double x1, double y1, double x2, double y2);
230
231    /* Called by spiro to move from the last point to the next along a cubic bézier spline */
232    /* (x1,y1) and (x2,y2) are the two off-curve control point and (x3,y3) will be the new end point */
233    void (*curveto)(bezctx *bc, double x1, double y1, double x2, double y2,
234            double x3, double y3);
235
236    /* Called by spiro to notify calling function this is a knot point */
237    void (*mark_knot)(bezctx *bc, int knot_idx);
238};
239```
240
241You must create a super-class of this abstract type that handles the creation of your particular representation of bézier splines. As an [example I provide the one used by Raph to generate PostScript output](bezctx.md) (cubic béziers). Spiro will convert a set of spiro_cps into a set of bézier curves. As it does so it will call the appropriate routine in your bézier context with this information – this should allow you to create your own internal representation of those curves.
242
243#### Calling into libspiro
244
245Your program needs this Libspiro header file:
246
247```c
248#include <spiroentrypoints.h>
249```
250
251You must define a bézier context that is appropriate for your internal splines (See [Raph's PostScript example](bezctx.md)).
252
253#### SpiroCPsToBezier2
254
255You must create an array of spiro control points:
256
257```c
258   spiro_cp points[4];
259
260     /* This defines something very like a circle, centered at the origin with radius 100 */
261
262   points[0].x = -100; points[0].y =    0; points[0].ty = SPIRO_G4;
263   points[1].x =    0; points[1].y =  100; points[1].ty = SPIRO_G4;
264   points[2].x =  100; points[2].y =    0; points[2].ty = SPIRO_G4;
265   points[3].x =    0; points[3].y = -100; points[3].ty = SPIRO_G4;
266```
267
268![](closedspiro.png)
269
270Then call `SpiroCPsToBezier2`, a routine which takes 5 arguments and returns bc and an integer pass/fail flag.
271
2721. An array of input spiros
2732. The number of elements in the spiros array (this example has 4)
2743. Additional ncq control variable (default==0)
2754. Whether this describes a closed (True=1) or open (False=0) contour
2765. A bézier results output context
2776. An integer success flag. 1 = completed task and have valid bézier results, or  0 = unable to complete task, bézier results are invalid.
278
279  ```c
280    bc = new_bezctx_ps();
281    success = SpiroCPsToBezier2(points,4,ncq,True,bc)
282    bezctx_ps_close(bc);
283  ```
284
285#### TaggedSpiroCPsToBezier2
286
287Or call `TaggedSpiroCPsToBezier2`. This routine requires that the array of spiro control points be tagged according to Raph's internal conventions. A closed curve will have an extra control point attached to the end of it with a type of `SPIRO_END`;
288
289```c
290   spiro_cp points[5];
291
292   points[0].x = -100; points[0].y =    0; points[0].ty = SPIRO_G4;
293   points[1].x =    0; points[1].y =  100; points[1].ty = SPIRO_G4;
294   points[2].x =  100; points[2].y =    0; points[2].ty = SPIRO_G4;
295   points[3].x =    0; points[3].y = -100; points[3].ty = SPIRO_G4;
296   points[4].x =    0; points[4].y =    0; points[4].ty = SPIRO_END;
297```
298
299(The x,y location of this last SPIRO_END point is irrelevant).
300
301An open curve will have the type of the first control point set to `SPIRO_OPEN_CONTOUR` and the last to `SPIRO_END_OPEN_CONTOUR`.
302
303```c
304   spiro_cp points[4];
305
306   points[0].x = -100; points[0].y =    0; points[0].ty = SPIRO_OPEN_CONTOUR;
307   points[1].x =    0; points[1].y =  100; points[1].ty = SPIRO_G4;
308   points[2].x =  100; points[2].y =    0; points[2].ty = SPIRO_G4;
309   points[3].x =    0; points[3].y = -100; points[3].ty = SPIRO_END_OPEN_CONTOUR;
310```
311
312![](openspiro.png)
313
314(In an open contour the point types of the first and last control points are going to be ignored).
315
316In this case there is no need to provide a point count nor an open/closed contour flag. That information can be obtained from the control points themselves. So `TaggedSpiroCPsToBezier2` only takes 3 arguments and returns bc and an integer pass/fail flag.
317
3181. An array of input spiros
3192. A bézier results output context
3203. Additional ncq control variable (default==0)
3214. An integer success flag. 1 = completed task and have valid bézier results, or  0 = unable to complete task, bézier results are invalid.
322
323   ```c
324    bc = new_bezctx_ps();
325    success = TaggedSpiroCPsToBezier2(points,ncq,bc)
326    bezctx_ps_close(bc);
327   ```
328
329### Programming with libspiro in Java
330
331**CAVEAT:** I'm not proficient in Java.
332
333### Classes
334
335- `SpiroPointType` – this is an enumerated type which defines the same pointtypes used by the C interface: `CORNER`, `G4`, `G2`, `LEFT`, `RIGHT`, `END`, `OPEN`, `OPEN_END`
336
337- `SpiroCP`
338  ```java
339  public class SpiroCP {
340    public double x,y;
341    SpiroPointType type;
342    public SpiroCP(double xx, double yy, SpiroPointType ty);
343    public String toString();
344  }
345  ```
346
347- `SpiroBezierContext` – a Java interface used in conversion of an array of SpiroCPs to a Bézier contour.
348
349  ```java
350  public interface SpiroBezierContext {
351    void MoveTo(double x, double y, boolean isOpen);
352    void LineTo(double x, double y);
353    void QuadTo(double x1, double y1, double x2, double y2);
354    void CubicTo(double x1, double y1, double x2, double y2, double x3, double y3);
355    void MarkKnot(int knotIdx);
356  }
357  ```
358
359- `Spiro` – a class with only static members:
360
361  ```java
362  public class Spiro {
363    // takes an array of SpiroCPs and converts to a Bézier
364    static public void
365      SpiroCPsToBezier(SpiroCP [] spiros,int n,boolean isclosed,
366          SpiroBezierContext bc);
367    // takes an array of SpiroCPs (the array contains its own terminator and indication of whether the contour is open or closed)
368    static public void
369      TaggedSpiroCPsToBezier(SpiroCP [] spiros,SpiroBezierContext bc);
370
371    // Two routines for reading and writing one of Raph's plate files
372    static public void
373      SavePlateFile(Writer output,SpiroCP [][] spirocontours)
374      throws IOException;
375    static public SpiroCP [][]
376      ReadPlateFile(BufferedReader input) throws IOException;
377  }
378  ```
379