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