spiro 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,37 @@
1
+ #ifndef _SPIRO_H
2
+ #define _SPIRO_H
3
+
4
+ typedef struct {
5
+ /* User passes an array of SpiroCP in this format for Spiro to solve */
6
+ double x; /* Spiro CodePoint Xloc */
7
+ double y; /* Spiro CodePoint Yloc */
8
+ char ty; /* Spiro CodePoint Type */
9
+ } spiro_cp;
10
+
11
+ struct spiro_seg_s {
12
+ /* run_spiro() uses array of information given in the structure above and */
13
+ /* creates an array in this structure format to use by spiro_to_bpath for */
14
+ /* building bezier curves */
15
+ double x; /* SpiroCP segment_chord startX */
16
+ double y; /* SpiroCP segment_chord startY */
17
+ char ty; /* Spiro CodePoint Type */
18
+ double bend_th; /* bend theta between this vector and next vector */
19
+ double ks[4];
20
+ double seg_ch; /* segment_chord distance from xy to next SpiroCP */
21
+ double seg_th; /* segment_theta angle for this SpiroCP */
22
+ double l;
23
+ };
24
+
25
+ typedef struct spiro_seg_s spiro_seg;
26
+
27
+ spiro_seg *
28
+ run_spiro(const spiro_cp *src, int n);
29
+
30
+ void
31
+ free_spiro(spiro_seg *s);
32
+
33
+ void
34
+ spiro_to_bpath(const spiro_seg *s, int n, bezctx *bc);
35
+
36
+ double get_knot_th(const spiro_seg *s, int i);
37
+ #endif
@@ -0,0 +1,68 @@
1
+ /*
2
+ ppedit - A pattern plate editor for Spiro splines.
3
+ Copyright (C) 2007 Raph Levien
4
+
5
+ This program is free software; you can redistribute it and/or
6
+ modify it under the terms of the GNU General Public License
7
+ as published by the Free Software Foundation; either version 3
8
+ of the License, or (at your option) any later version.
9
+
10
+ This program is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ GNU General Public License for more details.
14
+
15
+ You should have received a copy of the GNU General Public License
16
+ along with this program; if not, write to the Free Software
17
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18
+ 02110-1301, USA.
19
+
20
+ */
21
+ //#include "spiro-config.h"
22
+ #ifdef VERBOSE
23
+ #include <stdio.h>
24
+ #endif
25
+
26
+ #include "bezctx.h"
27
+
28
+ void bezctx_moveto(bezctx *bc, double x, double y, int is_open)
29
+ {
30
+ #ifdef VERBOSE
31
+ printf("moveto(%g,%g)_%d\n",x,y,is_open);
32
+ #endif
33
+ bc->moveto(bc, x, y, is_open);
34
+ }
35
+
36
+ void bezctx_lineto(bezctx *bc, double x, double y)
37
+ {
38
+ #ifdef VERBOSE
39
+ printf("lineto(%g,%g)\n",x,y);
40
+ #endif
41
+ bc->lineto(bc, x, y);
42
+ }
43
+
44
+ void bezctx_quadto(bezctx *bc, double x1, double y1, double x2, double y2)
45
+ {
46
+ #ifdef VERBOSE
47
+ printf("quadto(%g,%g, %g,%g)\n",x1,y1,x2,y2);
48
+ #endif
49
+ bc->quadto(bc, x1, y1, x2, y2);
50
+ }
51
+
52
+ void bezctx_curveto(bezctx *bc, double x1, double y1, double x2, double y2,
53
+ double x3, double y3)
54
+ {
55
+ #ifdef VERBOSE
56
+ printf("curveto(%g,%g, %g,%g, %g,%g)\n",x1,y1,x2,y2,x3,y3);
57
+ #endif
58
+ bc->curveto(bc, x1, y1, x2, y2, x3, y3);
59
+ }
60
+
61
+ void bezctx_mark_knot(bezctx *bc, int knot_idx)
62
+ {
63
+ #ifdef VERBOSE
64
+ printf("mark_knot()_%d\n",knot_idx);
65
+ #endif
66
+ if (bc->mark_knot)
67
+ bc->mark_knot(bc, knot_idx);
68
+ }
@@ -0,0 +1,23 @@
1
+ #ifndef _BEZCTX_H
2
+ #define _BEZCTX_H
3
+ #include "bezctx_intf.h"
4
+
5
+ struct _bezctx {
6
+ /* Called by spiro to start a contour */
7
+ void (*moveto)(bezctx *bc, double x, double y, int is_open);
8
+
9
+ /* Called by spiro to move from the last point to the next one on a straight line */
10
+ void (*lineto)(bezctx *bc, double x, double y);
11
+
12
+ /* Called by spiro to move from the last point to the next along a quadratic bezier spline */
13
+ /* (x1,y1) is the quadratic bezier control point and (x2,y2) will be the new end point */
14
+ void (*quadto)(bezctx *bc, double x1, double y1, double x2, double y2);
15
+
16
+ /* Called by spiro to move from the last point to the next along a cubic bezier spline */
17
+ /* (x1,y1) and (x2,y2) are the two off-curve control point and (x3,y3) will be the new end point */
18
+ void (*curveto)(bezctx *bc, double x1, double y1, double x2, double y2,
19
+ double x3, double y3);
20
+
21
+ void (*mark_knot)(bezctx *bc, int knot_idx);
22
+ };
23
+ #endif
@@ -0,0 +1,23 @@
1
+ #ifndef _BEZCTX_INTF_H
2
+ #define _BEZCTX_INTF_H
3
+ typedef struct _bezctx bezctx;
4
+
5
+ bezctx *
6
+ new_bezctx(void);
7
+
8
+ void
9
+ bezctx_moveto(bezctx *bc, double x, double y, int is_open);
10
+
11
+ void
12
+ bezctx_lineto(bezctx *bc, double x, double y);
13
+
14
+ void
15
+ bezctx_quadto(bezctx *bc, double x1, double y1, double x2, double y2);
16
+
17
+ void
18
+ bezctx_curveto(bezctx *bc, double x1, double y1, double x2, double y2,
19
+ double x3, double y3);
20
+
21
+ void
22
+ bezctx_mark_knot(bezctx *bc, int knot_idx);
23
+ #endif
@@ -0,0 +1,91 @@
1
+ #include <stdlib.h>
2
+ #include "bezctx_rb.h"
3
+
4
+ Splines splines;
5
+
6
+ void initSplines(Splines *a, size_t initialSize) {
7
+ a->array = (node *)malloc(initialSize * sizeof(node));
8
+ a->used = 0;
9
+ a->size = initialSize;
10
+ }
11
+
12
+ void appendSplines(Splines *a, node element) {
13
+ if (a->used == a->size) {
14
+ a->size *= 2;
15
+ a->array = (node *)realloc(a->array, a->size * sizeof(node));
16
+ }
17
+ a->array[a->used++] = element;
18
+ }
19
+
20
+ void freeSplines(Splines *a) {
21
+ free(a->array);
22
+ a->array = NULL;
23
+ a->used = a->size = 0;
24
+ }
25
+
26
+ typedef struct {
27
+ bezctx base; // This is a superclass of bezctx, entry for the base
28
+ int is_open;
29
+ } bezctx_rb;
30
+
31
+ /* This routine starts a new contour */
32
+ static void bezctx_rb_moveto(bezctx *z, double x, double y, int is_open) {
33
+ bezctx_rb *bc = (bezctx_rb *)z;
34
+
35
+ bc->is_open = is_open;
36
+
37
+ node n = { x, y, SPLINE_CORNER };
38
+ appendSplines(&splines, n);
39
+ }
40
+
41
+ /* This routine creates a linear spline from the previous point specified to this one */
42
+ void bezctx_rb_lineto(bezctx *z, double x, double y) {
43
+ bezctx_rb *bc = (bezctx_rb *)z;
44
+
45
+ node n = { x, y, SPLINE_CORNER };
46
+ appendSplines(&splines, n);
47
+ }
48
+
49
+ /* This creates a qubic curve */
50
+ void bezctx_rb_quadto(bezctx *z, double xm, double ym, double x3, double y3) {
51
+ bezctx_rb *bc = (bezctx_rb *)z;
52
+
53
+ node n1 = { xm, ym, SPLINE_QUADRATIC };
54
+ appendSplines(&splines, n1);
55
+
56
+ node n2 = { x3, y3, SPLINE_CORNER };
57
+ appendSplines(&splines, n2);
58
+ }
59
+
60
+ /* And this creates a cubic */
61
+ void bezctx_rb_curveto(bezctx *z, double x1, double y1, double x2, double y2,
62
+ double x3, double y3) {
63
+ bezctx_rb *bc = (bezctx_rb *)z;
64
+
65
+ node n1 = { x1, y1, SPLINE_CUBIC };
66
+ appendSplines(&splines, n1);
67
+ node n2 = { x2, y2, SPLINE_CUBIC };
68
+ appendSplines(&splines, n2);
69
+ node n3 = { x3, y3, SPLINE_CORNER };
70
+ appendSplines(&splines, n3);
71
+ }
72
+
73
+ /* Allocates and initializes a new bezier context */
74
+ bezctx * new_bezctx_rb(void) {
75
+ bezctx_rb *result = (bezctx_rb *)malloc(sizeof(bezctx_rb));
76
+ initSplines(&splines, 20);
77
+
78
+ result->base.moveto = bezctx_rb_moveto;
79
+ result->base.lineto = bezctx_rb_lineto;
80
+ result->base.quadto = bezctx_rb_quadto;
81
+ result->base.curveto = bezctx_rb_curveto;
82
+ result->base.mark_knot = NULL;
83
+ result->is_open = 0;
84
+ return &result->base;
85
+ }
86
+
87
+ /* Finishes an old bezier context */
88
+ void bezctx_rb_close(bezctx *z) {
89
+ bezctx_rb *bc = (bezctx_rb *)z;
90
+ free(bc);
91
+ }
@@ -0,0 +1,32 @@
1
+ #include "spiroentrypoints.h"
2
+ #include "bezctx.h"
3
+
4
+ // Possible values of the "ty" field.
5
+ #define SPLINE_CORNER 1
6
+ #define SPLINE_CUBIC 3
7
+ #define SPLINE_QUADRATIC 4
8
+
9
+ typedef struct {
10
+ double x;
11
+ double y;
12
+ int ty;
13
+ } node;
14
+
15
+ typedef struct Splines {
16
+ node *array;
17
+ size_t used;
18
+ size_t size;
19
+ } Splines;
20
+
21
+ extern Splines splines;
22
+
23
+
24
+ bezctx *new_bezctx_rb(void);
25
+
26
+ //struct splineset;
27
+ //struct Splines;
28
+
29
+ void freeSplines(Splines *a);
30
+
31
+ //struct splineset *bezctx_rb_close(bezctx *bc);
32
+ void bezctx_rb_close(bezctx *z);
@@ -0,0 +1,6 @@
1
+ require 'mkmf'
2
+
3
+ #CONFIG['LDSHARED'] = "$(CXX) -shared"
4
+
5
+ #dir_config('spiro')
6
+ create_makefile('spiro/spiro')
@@ -0,0 +1,121 @@
1
+ #include <ruby.h>
2
+ #include "spiroentrypoints.h" // call spiro through here
3
+ #include "bezctx_rb.h" // bezctx structure
4
+ #include "_spiro.h"
5
+
6
+ static ID id_corner;
7
+ static ID id_g4;
8
+ static ID id_g2;
9
+ static ID id_left;
10
+ static ID id_right;
11
+
12
+ static inline char sym_to_spiro_type(VALUE sym) {
13
+ ID inp = rb_to_id(sym);
14
+
15
+ if (inp == id_corner) {
16
+ return SPIRO_CORNER;
17
+ } else if (inp == id_g2) {
18
+ return SPIRO_G2;
19
+ } else if (inp == id_g4) {
20
+ return SPIRO_G4;
21
+ } else if (inp == id_left) {
22
+ return SPIRO_LEFT;
23
+ } else if (inp == id_right) {
24
+ return SPIRO_RIGHT;
25
+ }
26
+
27
+ rb_raise(rb_eArgError, "%s", "Expected :g2, :g4, :node, :left or :right");
28
+ }
29
+
30
+ static inline VALUE spline_type_to_sym(int ty) {
31
+ if (ty == SPLINE_CORNER) {
32
+ return ID2SYM(rb_intern("node"));
33
+ } else if (ty == SPLINE_CUBIC) {
34
+ return ID2SYM(rb_intern("cubic"));
35
+ } else if (ty == SPLINE_QUADRATIC) {
36
+ return ID2SYM(rb_intern("quadratic"));
37
+ }
38
+ }
39
+
40
+ static inline int bool_to_int(VALUE b) {
41
+ switch (TYPE(b)) {
42
+ case T_TRUE:
43
+ return 1;
44
+ break;
45
+ case T_FALSE:
46
+ return 0;
47
+ break;
48
+ default:
49
+ rb_raise(rb_eTypeError, "not a boolean");
50
+ break;
51
+ }
52
+ }
53
+
54
+ static VALUE spiros_to_splines(VALUE mod, VALUE spirosValue, VALUE closedValue) {
55
+ Check_Type(spirosValue, T_ARRAY);
56
+
57
+ // Take Ruby array of points and turn into Spiro C struct array
58
+ spiro_cp spiros[RARRAY_LEN(spirosValue)];
59
+ for (int i = 0; i != RARRAY_LEN(spirosValue); i++) {
60
+ VALUE nodeValue = rb_ary_entry(spirosValue, i);
61
+ // Validate node is an array and length 3 (x, y, type)
62
+ Check_Type(nodeValue, T_ARRAY);
63
+ if (RARRAY_LEN(nodeValue) != 3) rb_raise(rb_eArgError, "%s", "Invalid node");
64
+
65
+ // Validate individual node elements
66
+ VALUE xValue = rb_ary_entry(nodeValue, 0);
67
+ if (TYPE(xValue) != T_FIXNUM && TYPE(xValue) != T_FLOAT) {
68
+ rb_raise(rb_eTypeError, "x coord must be float or fixnum");
69
+ }
70
+ VALUE yValue = rb_ary_entry(nodeValue, 1);
71
+ if (TYPE(yValue) != T_FIXNUM && TYPE(yValue) != T_FLOAT) {
72
+ rb_raise(rb_eTypeError, "y coord must be float or fixnum");
73
+ }
74
+ VALUE typeValue = rb_ary_entry(nodeValue, 2);
75
+ Check_Type(typeValue, T_SYMBOL);
76
+
77
+ spiros[i].x = (long)(NUM2DBL(xValue));
78
+ spiros[i].y = (long)(NUM2DBL(yValue));
79
+ spiros[i].ty = sym_to_spiro_type(typeValue);
80
+ }
81
+
82
+ int closed = bool_to_int(closedValue);
83
+
84
+ // bezctx_rb is custom, stores the result of running Spiro
85
+ bezctx *bc = new_bezctx_rb();
86
+ // Run Spiro on the Spiros array and populate custom struct with splines array
87
+ int success = SpiroCPsToBezier0(spiros, RARRAY_LEN(spirosValue), closed, bc);
88
+
89
+ if (success) {
90
+ // Build Ruby array from Spiro array
91
+ VALUE splinesValue = rb_ary_new();
92
+ // Free memory from the custom struct
93
+ bezctx_rb_close(bc);
94
+ for (int i = 0; i < splines.used; i++) {
95
+ VALUE x = rb_float_new(splines.array[i].x);
96
+ VALUE y = rb_float_new(splines.array[i].y);
97
+ VALUE ty = spline_type_to_sym(splines.array[i].ty);
98
+ VALUE nodeValue = rb_ary_new3(3, x, y, ty);
99
+ rb_ary_push(splinesValue, nodeValue);
100
+ }
101
+ freeSplines(&splines);
102
+
103
+ return splinesValue;
104
+ }
105
+ else {
106
+ bezctx_rb_close(bc);
107
+ freeSplines(&splines);
108
+ return Qnil;
109
+ }
110
+ }
111
+
112
+ void Init_spiro(void) {
113
+ id_corner = rb_intern("node");
114
+ id_g4 = rb_intern("g4");
115
+ id_g2 = rb_intern("g2");
116
+ id_left = rb_intern("left");
117
+ id_right = rb_intern("right");
118
+
119
+ VALUE mSpiro = rb_define_module("Spiro");
120
+ rb_define_singleton_method(mSpiro, "spiros_to_splines", spiros_to_splines, 2);
121
+ }
@@ -0,0 +1,83 @@
1
+ /*
2
+ libspiro - conversion between spiro control points and bezier's
3
+ Copyright (C) 2007 Raph Levien
4
+
5
+ This program is free software; you can redistribute it and/or
6
+ modify it under the terms of the GNU General Public License
7
+ as published by the Free Software Foundation; either version 3
8
+ of the License, or (at your option) any later version.
9
+
10
+ This program is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ GNU General Public License for more details.
14
+
15
+ You should have received a copy of the GNU General Public License
16
+ along with this program; if not, write to the Free Software
17
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18
+ 02110-1301, USA.
19
+
20
+ */
21
+ /* Interface routines to Raph's spiro package. */
22
+
23
+ #include "spiroentrypoints.h"
24
+
25
+ /* These two functions are kept for backwards compatibility */
26
+ void SpiroCPsToBezier(spiro_cp *spiros,int n,int isclosed,bezctx *bc) {
27
+ SpiroCPsToBezier0(spiros,n,isclosed,bc);
28
+ }
29
+ void TaggedSpiroCPsToBezier(spiro_cp *spiros,bezctx *bc) {
30
+ TaggedSpiroCPsToBezier0(spiros,bc);
31
+ }
32
+
33
+ int
34
+ SpiroCPsToBezier0(spiro_cp *spiros,int n,int isclosed,bezctx *bc)
35
+ {
36
+ spiro_seg *s;
37
+
38
+ if ( n<=0 )
39
+ return 0;
40
+ if ( isclosed )
41
+ s = run_spiro(spiros,n);
42
+ else {
43
+ char oldty_start = spiros[0].ty;
44
+ char oldty_end = spiros[n-1].ty;
45
+ spiros[0].ty = '{';
46
+ spiros[n-1].ty = '}';
47
+ s = run_spiro(spiros,n);
48
+ spiros[n-1].ty = oldty_end;
49
+ spiros[0].ty = oldty_start;
50
+ }
51
+ if (s) {
52
+ spiro_to_bpath(s,n,bc);
53
+ free_spiro(s);
54
+ return 1; /* success */
55
+ }
56
+ return 0 ; /* spiro did not converge or encountered non-finite values */
57
+ }
58
+
59
+ int
60
+ TaggedSpiroCPsToBezier0(spiro_cp *spiros,bezctx *bc)
61
+ {
62
+ spiro_seg *s;
63
+ int n;
64
+
65
+ for ( n=0; spiros[n].ty!='z' && spiros[n].ty!='}'; ++n );
66
+ if ( spiros[n].ty == '}' ) ++n;
67
+
68
+ if ( n<=0 ) return 0; /* invalid input */
69
+ s = run_spiro(spiros,n);
70
+ if (s) {
71
+ spiro_to_bpath(s,n,bc);
72
+ free_spiro(s);
73
+ return 1; /* success */
74
+ }
75
+ return 0 ; /* spiro did not converge or encountered non-finite values */
76
+ }
77
+
78
+ void SpiroCPsToBezier1(spiro_cp *spiros,int n,int isclosed,bezctx *bc,int *done) {
79
+ *done = SpiroCPsToBezier0(spiros,n,isclosed,bc);
80
+ }
81
+ void TaggedSpiroCPsToBezier1(spiro_cp *spiros,bezctx *bc,int *done) {
82
+ *done = TaggedSpiroCPsToBezier0(spiros,bc);
83
+ }