spiro 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +31 -0
- data/Rakefile +9 -0
- data/ext/spiro/_spiro.c +995 -0
- data/ext/spiro/_spiro.h +37 -0
- data/ext/spiro/bezctx.c +68 -0
- data/ext/spiro/bezctx.h +23 -0
- data/ext/spiro/bezctx_intf.h +23 -0
- data/ext/spiro/bezctx_rb.c +91 -0
- data/ext/spiro/bezctx_rb.h +32 -0
- data/ext/spiro/extconf.rb +6 -0
- data/ext/spiro/spiro.c +121 -0
- data/ext/spiro/spiroentrypoints.c +83 -0
- data/ext/spiro/spiroentrypoints.h +53 -0
- data/ext/spiro/zmisc.h +17 -0
- data/lib/spiro.rb +6 -0
- data/lib/spiro/version.rb +3 -0
- data/spiro.gemspec +27 -0
- data/test/test_spiro.rb +69 -0
- metadata +126 -0
data/ext/spiro/_spiro.h
ADDED
@@ -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
|
data/ext/spiro/bezctx.c
ADDED
@@ -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
|
+
}
|
data/ext/spiro/bezctx.h
ADDED
@@ -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);
|
data/ext/spiro/spiro.c
ADDED
@@ -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
|
+
}
|