1 //-----------------------------------------------------------------------------
2 // A library wrapper around SolveSpace, to permit someone to use its constraint
3 // solver without coupling their program too much to SolveSpace's internals.
4 //
5 // Copyright 2008-2013 Jonathan Westhues.
6 //-----------------------------------------------------------------------------
7 #include "solvespace.h"
8 #define EXPORT_DLL
9 #include <slvs.h>
10 
11 Sketch SolveSpace::SK = {};
12 static System SYS;
13 
14 static int IsInit = 0;
15 
GenerateEquations(IdList<Equation,hEquation> *)16 void Group::GenerateEquations(IdList<Equation,hEquation> *) {
17     // Nothing to do for now.
18 }
19 
CnfFreezeInt(uint32_t,const std::string &)20 void SolveSpace::CnfFreezeInt(uint32_t, const std::string &)
21 {
22     abort();
23 }
24 
CnfThawInt(uint32_t,const std::string &)25 uint32_t SolveSpace::CnfThawInt(uint32_t, const std::string &)
26 {
27     abort();
28     return 0;
29 }
30 
DoMessageBox(const char *,int,int,bool)31 void SolveSpace::DoMessageBox(const char *, int, int, bool)
32 {
33     abort();
34 }
35 
36 extern "C" {
37 
Slvs_QuaternionU(double qw,double qx,double qy,double qz,double * x,double * y,double * z)38 void Slvs_QuaternionU(double qw, double qx, double qy, double qz,
39                          double *x, double *y, double *z)
40 {
41     Quaternion q = Quaternion::From(qw, qx, qy, qz);
42     Vector v = q.RotationU();
43     *x = v.x;
44     *y = v.y;
45     *z = v.z;
46 }
47 
Slvs_QuaternionV(double qw,double qx,double qy,double qz,double * x,double * y,double * z)48 void Slvs_QuaternionV(double qw, double qx, double qy, double qz,
49                          double *x, double *y, double *z)
50 {
51     Quaternion q = Quaternion::From(qw, qx, qy, qz);
52     Vector v = q.RotationV();
53     *x = v.x;
54     *y = v.y;
55     *z = v.z;
56 }
57 
Slvs_QuaternionN(double qw,double qx,double qy,double qz,double * x,double * y,double * z)58 void Slvs_QuaternionN(double qw, double qx, double qy, double qz,
59                          double *x, double *y, double *z)
60 {
61     Quaternion q = Quaternion::From(qw, qx, qy, qz);
62     Vector v = q.RotationN();
63     *x = v.x;
64     *y = v.y;
65     *z = v.z;
66 }
67 
Slvs_MakeQuaternion(double ux,double uy,double uz,double vx,double vy,double vz,double * qw,double * qx,double * qy,double * qz)68 void Slvs_MakeQuaternion(double ux, double uy, double uz,
69                          double vx, double vy, double vz,
70                          double *qw, double *qx, double *qy, double *qz)
71 {
72     Vector u = Vector::From(ux, uy, uz),
73            v = Vector::From(vx, vy, vz);
74     Quaternion q = Quaternion::From(u, v);
75     *qw = q.w;
76     *qx = q.vx;
77     *qy = q.vy;
78     *qz = q.vz;
79 }
80 
Slvs_Solve(Slvs_System * ssys,Slvs_hGroup shg)81 void Slvs_Solve(Slvs_System *ssys, Slvs_hGroup shg)
82 {
83     if(!IsInit) {
84         InitHeaps();
85         IsInit = 1;
86     }
87 
88     int i;
89     for(i = 0; i < ssys->params; i++) {
90         Slvs_Param *sp = &(ssys->param[i]);
91         Param p = {};
92 
93         p.h.v = sp->h;
94         p.val = sp->val;
95         SK.param.Add(&p);
96         if(sp->group == shg) {
97             SYS.param.Add(&p);
98         }
99     }
100 
101     for(i = 0; i < ssys->entities; i++) {
102         Slvs_Entity *se = &(ssys->entity[i]);
103         EntityBase e = {};
104 
105         switch(se->type) {
106 case SLVS_E_POINT_IN_3D:        e.type = Entity::POINT_IN_3D; break;
107 case SLVS_E_POINT_IN_2D:        e.type = Entity::POINT_IN_2D; break;
108 case SLVS_E_NORMAL_IN_3D:       e.type = Entity::NORMAL_IN_3D; break;
109 case SLVS_E_NORMAL_IN_2D:       e.type = Entity::NORMAL_IN_2D; break;
110 case SLVS_E_DISTANCE:           e.type = Entity::DISTANCE; break;
111 case SLVS_E_WORKPLANE:          e.type = Entity::WORKPLANE; break;
112 case SLVS_E_LINE_SEGMENT:       e.type = Entity::LINE_SEGMENT; break;
113 case SLVS_E_CUBIC:              e.type = Entity::CUBIC; break;
114 case SLVS_E_CIRCLE:             e.type = Entity::CIRCLE; break;
115 case SLVS_E_ARC_OF_CIRCLE:      e.type = Entity::ARC_OF_CIRCLE; break;
116 
117 default: dbp("bad entity type %d", se->type); return;
118         }
119         e.h.v           = se->h;
120         e.group.v       = se->group;
121         e.workplane.v   = se->wrkpl;
122         e.point[0].v    = se->point[0];
123         e.point[1].v    = se->point[1];
124         e.point[2].v    = se->point[2];
125         e.point[3].v    = se->point[3];
126         e.normal.v      = se->normal;
127         e.distance.v    = se->distance;
128         e.param[0].v    = se->param[0];
129         e.param[1].v    = se->param[1];
130         e.param[2].v    = se->param[2];
131         e.param[3].v    = se->param[3];
132 
133         SK.entity.Add(&e);
134     }
135 
136     for(i = 0; i < ssys->constraints; i++) {
137         Slvs_Constraint *sc = &(ssys->constraint[i]);
138         ConstraintBase c = {};
139 
140         int t;
141         switch(sc->type) {
142 case SLVS_C_POINTS_COINCIDENT:  t = Constraint::POINTS_COINCIDENT; break;
143 case SLVS_C_PT_PT_DISTANCE:     t = Constraint::PT_PT_DISTANCE; break;
144 case SLVS_C_PT_PLANE_DISTANCE:  t = Constraint::PT_PLANE_DISTANCE; break;
145 case SLVS_C_PT_LINE_DISTANCE:   t = Constraint::PT_LINE_DISTANCE; break;
146 case SLVS_C_PT_FACE_DISTANCE:   t = Constraint::PT_FACE_DISTANCE; break;
147 case SLVS_C_PT_IN_PLANE:        t = Constraint::PT_IN_PLANE; break;
148 case SLVS_C_PT_ON_LINE:         t = Constraint::PT_ON_LINE; break;
149 case SLVS_C_PT_ON_FACE:         t = Constraint::PT_ON_FACE; break;
150 case SLVS_C_EQUAL_LENGTH_LINES: t = Constraint::EQUAL_LENGTH_LINES; break;
151 case SLVS_C_LENGTH_RATIO:       t = Constraint::LENGTH_RATIO; break;
152 case SLVS_C_EQ_LEN_PT_LINE_D:   t = Constraint::EQ_LEN_PT_LINE_D; break;
153 case SLVS_C_EQ_PT_LN_DISTANCES: t = Constraint::EQ_PT_LN_DISTANCES; break;
154 case SLVS_C_EQUAL_ANGLE:        t = Constraint::EQUAL_ANGLE; break;
155 case SLVS_C_EQUAL_LINE_ARC_LEN: t = Constraint::EQUAL_LINE_ARC_LEN; break;
156 case SLVS_C_LENGTH_DIFFERENCE:  t = Constraint::LENGTH_DIFFERENCE; break;
157 case SLVS_C_SYMMETRIC:          t = Constraint::SYMMETRIC; break;
158 case SLVS_C_SYMMETRIC_HORIZ:    t = Constraint::SYMMETRIC_HORIZ; break;
159 case SLVS_C_SYMMETRIC_VERT:     t = Constraint::SYMMETRIC_VERT; break;
160 case SLVS_C_SYMMETRIC_LINE:     t = Constraint::SYMMETRIC_LINE; break;
161 case SLVS_C_AT_MIDPOINT:        t = Constraint::AT_MIDPOINT; break;
162 case SLVS_C_HORIZONTAL:         t = Constraint::HORIZONTAL; break;
163 case SLVS_C_VERTICAL:           t = Constraint::VERTICAL; break;
164 case SLVS_C_DIAMETER:           t = Constraint::DIAMETER; break;
165 case SLVS_C_PT_ON_CIRCLE:       t = Constraint::PT_ON_CIRCLE; break;
166 case SLVS_C_SAME_ORIENTATION:   t = Constraint::SAME_ORIENTATION; break;
167 case SLVS_C_ANGLE:              t = Constraint::ANGLE; break;
168 case SLVS_C_PARALLEL:           t = Constraint::PARALLEL; break;
169 case SLVS_C_PERPENDICULAR:      t = Constraint::PERPENDICULAR; break;
170 case SLVS_C_ARC_LINE_TANGENT:   t = Constraint::ARC_LINE_TANGENT; break;
171 case SLVS_C_CUBIC_LINE_TANGENT: t = Constraint::CUBIC_LINE_TANGENT; break;
172 case SLVS_C_EQUAL_RADIUS:       t = Constraint::EQUAL_RADIUS; break;
173 case SLVS_C_PROJ_PT_DISTANCE:   t = Constraint::PROJ_PT_DISTANCE; break;
174 case SLVS_C_WHERE_DRAGGED:      t = Constraint::WHERE_DRAGGED; break;
175 case SLVS_C_CURVE_CURVE_TANGENT:t = Constraint::CURVE_CURVE_TANGENT; break;
176 
177 default: dbp("bad constraint type %d", sc->type); return;
178         }
179 
180         c.type = t;
181 
182         c.h.v           = sc->h;
183         c.group.v       = sc->group;
184         c.workplane.v   = sc->wrkpl;
185         c.valA          = sc->valA;
186         c.ptA.v         = sc->ptA;
187         c.ptB.v         = sc->ptB;
188         c.entityA.v     = sc->entityA;
189         c.entityB.v     = sc->entityB;
190         c.entityC.v     = sc->entityC;
191         c.entityD.v     = sc->entityD;
192         c.other         = (sc->other) ? true : false;
193         c.other2        = (sc->other2) ? true : false;
194 
195         SK.constraint.Add(&c);
196     }
197 
198     for(i = 0; i < (int)arraylen(ssys->dragged); i++) {
199         if(ssys->dragged[i]) {
200             hParam hp = { ssys->dragged[i] };
201             SYS.dragged.Add(&hp);
202         }
203     }
204 
205     Group g = {};
206     g.h.v = shg;
207 
208     List<hConstraint> bad = {};
209 
210     // Now we're finally ready to solve!
211     bool andFindBad = ssys->calculateFaileds ? true : false;
212     int how = SYS.Solve(&g, &(ssys->dof), &bad, andFindBad, false);
213 
214     switch(how) {
215         case System::SOLVED_OKAY:
216             ssys->result = SLVS_RESULT_OKAY;
217             break;
218 
219         case System::DIDNT_CONVERGE:
220             ssys->result = SLVS_RESULT_DIDNT_CONVERGE;
221             break;
222 
223         case System::REDUNDANT_DIDNT_CONVERGE:
224         case System::REDUNDANT_OKAY:
225             ssys->result = SLVS_RESULT_INCONSISTENT;
226             break;
227 
228         case System::TOO_MANY_UNKNOWNS:
229             ssys->result = SLVS_RESULT_TOO_MANY_UNKNOWNS;
230             break;
231 
232         default: oops();
233     }
234 
235     // Write the new parameter values back to our caller.
236     for(i = 0; i < ssys->params; i++) {
237         Slvs_Param *sp = &(ssys->param[i]);
238         hParam hp = { sp->h };
239         sp->val = SK.GetParam(hp)->val;
240     }
241 
242     if(ssys->failed) {
243         // Copy over any the list of problematic constraints.
244         for(i = 0; i < ssys->faileds && i < bad.n; i++) {
245             ssys->failed[i] = bad.elem[i].v;
246         }
247         ssys->faileds = bad.n;
248     }
249 
250     bad.Clear();
251     SYS.param.Clear();
252     SYS.entity.Clear();
253     SYS.eq.Clear();
254     SYS.dragged.Clear();
255 
256     SK.param.Clear();
257     SK.entity.Clear();
258     SK.constraint.Clear();
259 
260     FreeAllTemporary();
261 }
262 
263 } /* extern "C" */
264