1 /*-----------------------------------------------------------------------------
2  * Data structures and prototypes for slvs.lib, a geometric constraint solver.
3  *
4  * See the comments in this file, the accompanying sample code that uses
5  * this library, and the accompanying documentation (DOC.txt).
6  *
7  * Copyright 2009-2013 Jonathan Westhues.
8  *---------------------------------------------------------------------------*/
9 
10 #ifndef __SLVS_H
11 #define __SLVS_H
12 
13 #ifdef WIN32
14 #   ifdef EXPORT_DLL
15 #       define DLL __declspec( dllexport )
16 #   else
17 #       define DLL __declspec( dllimport )
18 #   endif
19 #else
20 #   define DLL
21 #endif
22 
23 #ifdef __cplusplus
24 extern "C" {
25 #endif
26 
27 #ifdef _MSC_VER
28 typedef unsigned __int32 uint32_t;
29 #else
30 #include <stdint.h>
31 #endif
32 
33 typedef uint32_t Slvs_hParam;
34 typedef uint32_t Slvs_hEntity;
35 typedef uint32_t Slvs_hConstraint;
36 typedef uint32_t Slvs_hGroup;
37 
38 /* To obtain the 3d (not projected into a workplane) of a constraint or
39  * an entity, specify this instead of the workplane. */
40 #define SLVS_FREE_IN_3D         0
41 
42 
43 typedef struct {
44     Slvs_hParam     h;
45     Slvs_hGroup     group;
46     double          val;
47 } Slvs_Param;
48 
49 
50 #define SLVS_E_POINT_IN_3D          50000
51 #define SLVS_E_POINT_IN_2D          50001
52 
53 #define SLVS_E_NORMAL_IN_3D         60000
54 #define SLVS_E_NORMAL_IN_2D         60001
55 
56 #define SLVS_E_DISTANCE             70000
57 
58 /* The special point, normal, and distance types used for parametric step
59  * and repeat, extrude, and assembly are currently not exposed. Please
60  * contact us if you are interested in using these. */
61 
62 #define SLVS_E_WORKPLANE            80000
63 #define SLVS_E_LINE_SEGMENT         80001
64 #define SLVS_E_CUBIC                80002
65 #define SLVS_E_CIRCLE               80003
66 #define SLVS_E_ARC_OF_CIRCLE        80004
67 
68 typedef struct {
69     Slvs_hEntity    h;
70     Slvs_hGroup     group;
71 
72     int             type;
73 
74     Slvs_hEntity    wrkpl;
75     Slvs_hEntity    point[4];
76     Slvs_hEntity    normal;
77     Slvs_hEntity    distance;
78 
79     Slvs_hParam     param[4];
80 } Slvs_Entity;
81 
82 #define SLVS_C_POINTS_COINCIDENT        100000
83 #define SLVS_C_PT_PT_DISTANCE           100001
84 #define SLVS_C_PT_PLANE_DISTANCE        100002
85 #define SLVS_C_PT_LINE_DISTANCE         100003
86 #define SLVS_C_PT_FACE_DISTANCE         100004
87 #define SLVS_C_PT_IN_PLANE              100005
88 #define SLVS_C_PT_ON_LINE               100006
89 #define SLVS_C_PT_ON_FACE               100007
90 #define SLVS_C_EQUAL_LENGTH_LINES       100008
91 #define SLVS_C_LENGTH_RATIO             100009
92 #define SLVS_C_EQ_LEN_PT_LINE_D         100010
93 #define SLVS_C_EQ_PT_LN_DISTANCES       100011
94 #define SLVS_C_EQUAL_ANGLE              100012
95 #define SLVS_C_EQUAL_LINE_ARC_LEN       100013
96 #define SLVS_C_SYMMETRIC                100014
97 #define SLVS_C_SYMMETRIC_HORIZ          100015
98 #define SLVS_C_SYMMETRIC_VERT           100016
99 #define SLVS_C_SYMMETRIC_LINE           100017
100 #define SLVS_C_AT_MIDPOINT              100018
101 #define SLVS_C_HORIZONTAL               100019
102 #define SLVS_C_VERTICAL                 100020
103 #define SLVS_C_DIAMETER                 100021
104 #define SLVS_C_PT_ON_CIRCLE             100022
105 #define SLVS_C_SAME_ORIENTATION         100023
106 #define SLVS_C_ANGLE                    100024
107 #define SLVS_C_PARALLEL                 100025
108 #define SLVS_C_PERPENDICULAR            100026
109 #define SLVS_C_ARC_LINE_TANGENT         100027
110 #define SLVS_C_CUBIC_LINE_TANGENT       100028
111 #define SLVS_C_EQUAL_RADIUS             100029
112 #define SLVS_C_PROJ_PT_DISTANCE         100030
113 #define SLVS_C_WHERE_DRAGGED            100031
114 #define SLVS_C_CURVE_CURVE_TANGENT      100032
115 #define SLVS_C_LENGTH_DIFFERENCE        100033
116 
117 typedef struct {
118     Slvs_hConstraint    h;
119     Slvs_hGroup         group;
120 
121     int                 type;
122 
123     Slvs_hEntity        wrkpl;
124 
125     double              valA;
126     Slvs_hEntity        ptA;
127     Slvs_hEntity        ptB;
128     Slvs_hEntity        entityA;
129     Slvs_hEntity        entityB;
130     Slvs_hEntity        entityC;
131     Slvs_hEntity        entityD;
132 
133     int                 other;
134     int                 other2;
135 } Slvs_Constraint;
136 
137 
138 typedef struct {
139     /*** INPUT VARIABLES
140      *
141      * Here, we specify the parameters and their initial values, the entities,
142      * and the constraints. For example, param[] points to the array of
143      * parameters, which has length params, so that the last valid element
144      * is param[params-1].
145      *
146      * param[] is actually an in/out variable; if the solver is successful,
147      * then the new values (that satisfy the constraints) are written to it. */
148     Slvs_Param          *param;
149     int                 params;
150     Slvs_Entity         *entity;
151     int                 entities;
152     Slvs_Constraint     *constraint;
153     int                 constraints;
154 
155     /* If a parameter corresponds to a point (distance, normal, etc.) being
156      * dragged, then specify it here. This will cause the solver to favor
157      * that parameter, and attempt to change it as little as possible even
158      * if that requires it to change other parameters more.
159      *
160      * Unused members of this array should be set to zero. */
161     Slvs_hParam         dragged[4];
162 
163     /* If the solver fails, then it can determine which constraints are
164      * causing the problem. But this is a relatively slow process (for
165      * a system with n constraints, about n times as long as just solving).
166      * If calculateFaileds is true, then the solver will do so, otherwise
167      * not. */
168     int                 calculateFaileds;
169 
170     /*** OUTPUT VARIABLES
171      *
172      * If the solver fails, then it can report which constraints are causing
173      * the problem. The caller should allocate the array failed[], and pass
174      * its size in faileds.
175      *
176      * The solver will set faileds equal to the number of problematic
177      * constraints, and write their Slvs_hConstraints into failed[]. To
178      * ensure that there is sufficient space for any possible set of
179      * failing constraints, faileds should be greater than or equal to
180      * constraints. */
181     Slvs_hConstraint    *failed;
182     int                 faileds;
183 
184     /* The solver indicates the number of unconstrained degrees of freedom. */
185     int                 dof;
186 
187     /* The solver indicates whether the solution succeeded. */
188 #define SLVS_RESULT_OKAY                0
189 #define SLVS_RESULT_INCONSISTENT        1
190 #define SLVS_RESULT_DIDNT_CONVERGE      2
191 #define SLVS_RESULT_TOO_MANY_UNKNOWNS   3
192     int                 result;
193 } Slvs_System;
194 
195 DLL void Slvs_Solve(Slvs_System *sys, Slvs_hGroup hg);
196 
197 
198 /* Our base coordinate system has basis vectors
199  *     (1, 0, 0)  (0, 1, 0)  (0, 0, 1)
200  * A unit quaternion defines a rotation to a new coordinate system with
201  * basis vectors
202  *         U          V          N
203  * which these functions compute from the quaternion. */
204 DLL void Slvs_QuaternionU(double qw, double qx, double qy, double qz,
205                              double *x, double *y, double *z);
206 DLL void Slvs_QuaternionV(double qw, double qx, double qy, double qz,
207                              double *x, double *y, double *z);
208 DLL void Slvs_QuaternionN(double qw, double qx, double qy, double qz,
209                              double *x, double *y, double *z);
210 
211 /* Similarly, compute a unit quaternion in terms of two basis vectors. */
212 DLL void Slvs_MakeQuaternion(double ux, double uy, double uz,
213                              double vx, double vy, double vz,
214                              double *qw, double *qx, double *qy, double *qz);
215 
216 
217 /*-------------------------------------
218  * These are just convenience functions, to save you the trouble of filling
219  * out the structures by hand. The code is included in the header file to
220  * let the compiler inline them if possible. */
221 
Slvs_MakeParam(Slvs_hParam h,Slvs_hGroup group,double val)222 static inline Slvs_Param Slvs_MakeParam(Slvs_hParam h, Slvs_hGroup group, double val)
223 {
224     Slvs_Param r;
225     r.h = h;
226     r.group = group;
227     r.val = val;
228     return r;
229 }
Slvs_MakePoint2d(Slvs_hEntity h,Slvs_hGroup group,Slvs_hEntity wrkpl,Slvs_hParam u,Slvs_hParam v)230 static inline Slvs_Entity Slvs_MakePoint2d(Slvs_hEntity h, Slvs_hGroup group,
231                                            Slvs_hEntity wrkpl,
232                                            Slvs_hParam u, Slvs_hParam v)
233 {
234     Slvs_Entity r;
235     memset(&r, 0, sizeof(r));
236     r.h = h;
237     r.group = group;
238     r.type = SLVS_E_POINT_IN_2D;
239     r.wrkpl = wrkpl;
240     r.param[0] = u;
241     r.param[1] = v;
242     return r;
243 }
Slvs_MakePoint3d(Slvs_hEntity h,Slvs_hGroup group,Slvs_hParam x,Slvs_hParam y,Slvs_hParam z)244 static inline Slvs_Entity Slvs_MakePoint3d(Slvs_hEntity h, Slvs_hGroup group,
245                                            Slvs_hParam x, Slvs_hParam y, Slvs_hParam z)
246 {
247     Slvs_Entity r;
248     memset(&r, 0, sizeof(r));
249     r.h = h;
250     r.group = group;
251     r.type = SLVS_E_POINT_IN_3D;
252     r.wrkpl = SLVS_FREE_IN_3D;
253     r.param[0] = x;
254     r.param[1] = y;
255     r.param[2] = z;
256     return r;
257 }
Slvs_MakeNormal3d(Slvs_hEntity h,Slvs_hGroup group,Slvs_hParam qw,Slvs_hParam qx,Slvs_hParam qy,Slvs_hParam qz)258 static inline Slvs_Entity Slvs_MakeNormal3d(Slvs_hEntity h, Slvs_hGroup group,
259                                             Slvs_hParam qw, Slvs_hParam qx,
260                                             Slvs_hParam qy, Slvs_hParam qz)
261 {
262     Slvs_Entity r;
263     memset(&r, 0, sizeof(r));
264     r.h = h;
265     r.group = group;
266     r.type = SLVS_E_NORMAL_IN_3D;
267     r.wrkpl = SLVS_FREE_IN_3D;
268     r.param[0] = qw;
269     r.param[1] = qx;
270     r.param[2] = qy;
271     r.param[3] = qz;
272     return r;
273 }
Slvs_MakeNormal2d(Slvs_hEntity h,Slvs_hGroup group,Slvs_hEntity wrkpl)274 static inline Slvs_Entity Slvs_MakeNormal2d(Slvs_hEntity h, Slvs_hGroup group,
275                                             Slvs_hEntity wrkpl)
276 {
277     Slvs_Entity r;
278     memset(&r, 0, sizeof(r));
279     r.h = h;
280     r.group = group;
281     r.type = SLVS_E_NORMAL_IN_2D;
282     r.wrkpl = wrkpl;
283     return r;
284 }
Slvs_MakeDistance(Slvs_hEntity h,Slvs_hGroup group,Slvs_hEntity wrkpl,Slvs_hParam d)285 static inline Slvs_Entity Slvs_MakeDistance(Slvs_hEntity h, Slvs_hGroup group,
286                                             Slvs_hEntity wrkpl, Slvs_hParam d)
287 {
288     Slvs_Entity r;
289     memset(&r, 0, sizeof(r));
290     r.h = h;
291     r.group = group;
292     r.type = SLVS_E_DISTANCE;
293     r.wrkpl = wrkpl;
294     r.param[0] = d;
295     return r;
296 }
Slvs_MakeLineSegment(Slvs_hEntity h,Slvs_hGroup group,Slvs_hEntity wrkpl,Slvs_hEntity ptA,Slvs_hEntity ptB)297 static inline Slvs_Entity Slvs_MakeLineSegment(Slvs_hEntity h, Slvs_hGroup group,
298                                                Slvs_hEntity wrkpl,
299                                                Slvs_hEntity ptA, Slvs_hEntity ptB)
300 {
301     Slvs_Entity r;
302     memset(&r, 0, sizeof(r));
303     r.h = h;
304     r.group = group;
305     r.type = SLVS_E_LINE_SEGMENT;
306     r.wrkpl = wrkpl;
307     r.point[0] = ptA;
308     r.point[1] = ptB;
309     return r;
310 }
Slvs_MakeCubic(Slvs_hEntity h,Slvs_hGroup group,Slvs_hEntity wrkpl,Slvs_hEntity pt0,Slvs_hEntity pt1,Slvs_hEntity pt2,Slvs_hEntity pt3)311 static inline Slvs_Entity Slvs_MakeCubic(Slvs_hEntity h, Slvs_hGroup group,
312                                          Slvs_hEntity wrkpl,
313                                          Slvs_hEntity pt0, Slvs_hEntity pt1,
314                                          Slvs_hEntity pt2, Slvs_hEntity pt3)
315 {
316     Slvs_Entity r;
317     memset(&r, 0, sizeof(r));
318     r.h = h;
319     r.group = group;
320     r.type = SLVS_E_CUBIC;
321     r.wrkpl = wrkpl;
322     r.point[0] = pt0;
323     r.point[1] = pt1;
324     r.point[2] = pt2;
325     r.point[3] = pt3;
326     return r;
327 }
Slvs_MakeArcOfCircle(Slvs_hEntity h,Slvs_hGroup group,Slvs_hEntity wrkpl,Slvs_hEntity normal,Slvs_hEntity center,Slvs_hEntity start,Slvs_hEntity end)328 static inline Slvs_Entity Slvs_MakeArcOfCircle(Slvs_hEntity h, Slvs_hGroup group,
329                                                Slvs_hEntity wrkpl,
330                                                Slvs_hEntity normal,
331                                                Slvs_hEntity center,
332                                                Slvs_hEntity start, Slvs_hEntity end)
333 {
334     Slvs_Entity r;
335     memset(&r, 0, sizeof(r));
336     r.h = h;
337     r.group = group;
338     r.type = SLVS_E_ARC_OF_CIRCLE;
339     r.wrkpl = wrkpl;
340     r.normal = normal;
341     r.point[0] = center;
342     r.point[1] = start;
343     r.point[2] = end;
344     return r;
345 }
Slvs_MakeCircle(Slvs_hEntity h,Slvs_hGroup group,Slvs_hEntity wrkpl,Slvs_hEntity center,Slvs_hEntity normal,Slvs_hEntity radius)346 static inline Slvs_Entity Slvs_MakeCircle(Slvs_hEntity h, Slvs_hGroup group,
347                                           Slvs_hEntity wrkpl,
348                                           Slvs_hEntity center,
349                                           Slvs_hEntity normal, Slvs_hEntity radius)
350 {
351     Slvs_Entity r;
352     memset(&r, 0, sizeof(r));
353     r.h = h;
354     r.group = group;
355     r.type = SLVS_E_CIRCLE;
356     r.wrkpl = wrkpl;
357     r.point[0] = center;
358     r.normal = normal;
359     r.distance = radius;
360     return r;
361 }
Slvs_MakeWorkplane(Slvs_hEntity h,Slvs_hGroup group,Slvs_hEntity origin,Slvs_hEntity normal)362 static inline Slvs_Entity Slvs_MakeWorkplane(Slvs_hEntity h, Slvs_hGroup group,
363                                              Slvs_hEntity origin, Slvs_hEntity normal)
364 {
365     Slvs_Entity r;
366     memset(&r, 0, sizeof(r));
367     r.h = h;
368     r.group = group;
369     r.type = SLVS_E_WORKPLANE;
370     r.wrkpl = SLVS_FREE_IN_3D;
371     r.point[0] = origin;
372     r.normal = normal;
373     return r;
374 }
375 
Slvs_MakeConstraint(Slvs_hConstraint h,Slvs_hGroup group,int type,Slvs_hEntity wrkpl,double valA,Slvs_hEntity ptA,Slvs_hEntity ptB,Slvs_hEntity entityA,Slvs_hEntity entityB)376 static inline Slvs_Constraint Slvs_MakeConstraint(Slvs_hConstraint h,
377                                                   Slvs_hGroup group,
378                                                   int type,
379                                                   Slvs_hEntity wrkpl,
380                                                   double valA,
381                                                   Slvs_hEntity ptA,
382                                                   Slvs_hEntity ptB,
383                                                   Slvs_hEntity entityA,
384                                                   Slvs_hEntity entityB)
385 {
386     Slvs_Constraint r;
387     memset(&r, 0, sizeof(r));
388     r.h = h;
389     r.group = group;
390     r.type = type;
391     r.wrkpl = wrkpl;
392     r.valA = valA;
393     r.ptA = ptA;
394     r.ptB = ptB;
395     r.entityA = entityA;
396     r.entityB = entityB;
397     return r;
398 }
399 
400 #ifdef __cplusplus
401 }
402 #endif
403 
404 #endif
405