From f8dbc891890f41039bee9f18169d22894babf227 Mon Sep 17 00:00:00 2001 From: Jonathan Westhues Date: Tue, 21 Apr 2009 22:15:01 -0800 Subject: [PATCH] Polish a few little things in the constraint solver library stuff. [git-p4: depot-paths = "//depot/solvespace/": change = 1947] --- exposed/DOC.txt | 49 +++++++++++++++++++++++------------ exposed/example.c | 66 +++++++++++++++++++++++++++++++++++++++++++---- exposed/lib.cpp | 11 ++++++++ exposed/slvs.h | 22 +++++++++++++++- 4 files changed, 126 insertions(+), 22 deletions(-) diff --git a/exposed/DOC.txt b/exposed/DOC.txt index e24e5d8a..021edf99 100644 --- a/exposed/DOC.txt +++ b/exposed/DOC.txt @@ -1,4 +1,7 @@ +INTRODUCTION +============ + A sketch in SolveSpace consists of three basic elements: parameters, entities, and constraints. @@ -19,11 +22,11 @@ distance constraint will set the distance between two point entities. Paramters, entities, and constraints are typically referenced by their handles (Slvs_hParam, Slvs_hEntity, Slvs_hConstraint). These handles are -32-bit integer values starting from 1. Each object has a unique handle -within its type (but it's acceptable, for example to have a constraint -with an Slvs_hConstraint of 7, and also to have an entity with an -Slvs_hEntity of 7). The use of handles instead of pointers helps to -avoid memory corruption. +32-bit integer values starting from 1. The zero handle is reserved. Each +object has a unique handle within its type (but it's acceptable, for +example to have a constraint with an Slvs_hConstraint of 7, and also to +have an entity with an Slvs_hEntity of 7). The use of handles instead +of pointers helps to avoid memory corruption. Entities and constraints are assigned into groups. A group is a set of entities and constraints that is solved simultaneously. In a parametric @@ -31,23 +34,23 @@ CAD system, a single group would typically correspond to a single sketch. Constraints within a group may refer to entities outside that group, but only the entities within that group will be modified by the solver. -(Consider point A in group 1, and point B in group 2. We have a constraint +Consider point A in group 1, and point B in group 2. We have a constraint in group 2 that makes the points coincident. When we solve group 2, the solver is allowed to move point B to place it on top of point A. It is not allowed to move point A to put it on top of point B, because point -A is outside the group being solved.) +A is outside the group being solved. This corresponds to the typical structure of a parametric CAD system. In a later sketch, we may constrain our entities against existing geometry from earlier sketches. The constraints will move the entities in our current sketch, but will not change the geometry from the earlier sketches. -To use the solver, we first define a set of parameters, entities, -and constraints. We provide an initial guess for each parameter; this -will improve convergence, and also determine which solution gets chosen -when (finitely many) multiple solutions exist. Typically, these initial -guesses are provided by the initial configuration in which the user drew -the entities before constraining them. +To use the solver, we first define a set of parameters, entities, and +constraints. We provide an initial guess for each parameter; this is +necessary to achieve convergence, and also determines which solution +gets chosen when (finitely many) multiple solutions exist. Typically, +these initial guesses are provided by the initial configuration in which +the user drew the entities before constraining them. We then run the solver for a given group. The entities within that group are modified in an attempt to satisfy the constraints. @@ -55,18 +58,22 @@ are modified in an attempt to satisfy the constraints. After running the solver, there are three possible outcomes: * All constraints were satisfied to within our numerical - tolerance (i.e., success). + tolerance (i.e., success). The result is equal to SLVS_RESULT_OKAY, + and the parameters in param[] have been updated. * The solver can prove that two constraints are inconsistent (for example, if a line with nonzero length is constrained both horizontal and vertical). In that case, a list of inconsistent - constraints is generated. + constraints is generated in failed[]. * The solver cannot prove that two constraints are inconsistent, but it cannot find a solution. In that case, the list of unsatisfied - constraints is generated. + constraints is generated in failed[]. +TYPES OF ENTITIES +================= + SLVS_E_POINT_IN_3D A point in 3d. Defined by three parameters: @@ -236,6 +243,8 @@ SLVS_E_ARC_OF_CIRCLE distance(center, beginning) = distance(center, end) +TYPES OF CONSTRAINTS +==================== Many constraints can apply either in 3d, or in a workplane. This is determined by the wrkpl member of the constraint. If that member is set @@ -401,3 +410,11 @@ SLVS_C_EQUAL_RADIUS The circles or arcs entityA and entityB have equal radius. +USING THE SOLVER +================ + +See the enclosed sample code, example.c. + + +Copyright 2009, Jonathan Westhues. + diff --git a/exposed/example.c b/exposed/example.c index cb1d49ca..5c6cccd0 100644 --- a/exposed/example.c +++ b/exposed/example.c @@ -78,9 +78,9 @@ void Example3d(void) } //----------------------------------------------------------------------------- -// An example of a constraint in 2d. In an earlier group, we have created a -// workplane. Then in our group to be solved, we create a line segment, which -// we dimension to be horizontal and 2.0 units long. +// An example of a constraint in 2d. In our first group, we create a workplane +// along the reference frame's xy plane. In a second group, we create some +// entities in that group and dimension them. //----------------------------------------------------------------------------- void Example2d(void) { @@ -124,6 +124,38 @@ void Example2d(void) sys.entity[sys.entities++] = Slvs_MakeLineSegment(400, g, 200, 301, 302); + // Now three more points. + sys.param[sys.params++] = Slvs_MakeParam(15, g, 100.0); + sys.param[sys.params++] = Slvs_MakeParam(16, g, 120.0); + sys.entity[sys.entities++] = Slvs_MakePoint2d(303, g, 200, 15, 16); + + sys.param[sys.params++] = Slvs_MakeParam(17, g, 120.0); + sys.param[sys.params++] = Slvs_MakeParam(18, g, 110.0); + sys.entity[sys.entities++] = Slvs_MakePoint2d(304, g, 200, 17, 18); + + sys.param[sys.params++] = Slvs_MakeParam(19, g, 115.0); + sys.param[sys.params++] = Slvs_MakeParam(20, g, 115.0); + sys.entity[sys.entities++] = Slvs_MakePoint2d(305, g, 200, 19, 20); + + // And arc, centered at point 303, starting at point 304, ending at + // point 305. + sys.entity[sys.entities++] = Slvs_MakeArcOfCircle(401, g, 200, + 303, 304, 305); + + // Now one more point, and a distance + sys.param[sys.params++] = Slvs_MakeParam(21, g, 200.0); + sys.param[sys.params++] = Slvs_MakeParam(22, g, 200.0); + sys.entity[sys.entities++] = Slvs_MakePoint2d(306, g, 200, 21, 22); + + sys.param[sys.params++] = Slvs_MakeParam(23, g, 30.0); + sys.entity[sys.entities++] = Slvs_MakeDistance(307, g, 200, 23); + + // And a complete circle, centered at point 306 with radius equal to + // distance 307. The normal is 102, the same as our workplane. + sys.entity[sys.entities++] = Slvs_MakeCircle(402, g, 200, + 306, 102, 307); + + // The length of our line segment is 30.0 units. sys.constraint[sys.constraints++] = Slvs_MakeConstraint( 1, g, @@ -163,6 +195,21 @@ void Example2d(void) 18.0, 302, 101, 0, 0); */ + // The arc and the circle have equal radius. + sys.constraint[sys.constraints++] = Slvs_MakeConstraint( + 6, g, + SLVS_C_EQUAL_RADIUS, + 200, + 0.0, + 0, 0, 401, 402); + // The arc has radius 17.0 units. + sys.constraint[sys.constraints++] = Slvs_MakeConstraint( + 7, g, + SLVS_C_DIAMETER, + 200, + 17.0*2, + 0, 0, 401, 0); + // If the solver fails, then ask it to report which constraints caused // the problem. sys.calculateFaileds = 1; @@ -171,10 +218,19 @@ void Example2d(void) Slvs_Solve(&sys, g); if(sys.result == SLVS_RESULT_OKAY) { - printf("okay; now at (%.3f %.3f)\n" - " (%.3f %.3f)\n", + printf("solved okay\n"); + printf("line from (%.3f %.3f) to (%.3f %.3f)\n", sys.param[7].val, sys.param[8].val, sys.param[9].val, sys.param[10].val); + + printf("arc center (%.3f %.3f) start (%.3f %.3f) finish (%.3f %.3f)\n", + sys.param[11].val, sys.param[12].val, + sys.param[13].val, sys.param[14].val, + sys.param[15].val, sys.param[16].val); + + printf("circle center (%.3f %.3f) radius %.3f\n", + sys.param[17].val, sys.param[18].val, + sys.param[19].val); printf("%d DOF\n", sys.dof); } else { int i; diff --git a/exposed/lib.cpp b/exposed/lib.cpp index 2e10916b..a4095c6e 100644 --- a/exposed/lib.cpp +++ b/exposed/lib.cpp @@ -58,6 +58,17 @@ void Slvs_MakeQuaternion(double ux, double uy, double uz, void Slvs_Solve(Slvs_System *ssys, Slvs_hGroup shg) { if(!IsInit) { +#if 1 + dbp("SolveSpace library initialized (evaluation version only)."); + dbp("Built " __DATE__ " " __TIME__ + ". Copyright 2009 Jonathan Westhues."); + HWND h = GetForegroundWindow(); + MessageBox(h, +"This is an evaluation copy of SolveSpace. To purchase a license, please " +"contact info@solvespace.com.\r\n\r\n" +"Copyright 2009 Jonathan Westhues.", + "SolveSpace", MB_OK); +#endif InitHeaps(); IsInit = 1; } diff --git a/exposed/slvs.h b/exposed/slvs.h index eb87b79c..8d749700 100644 --- a/exposed/slvs.h +++ b/exposed/slvs.h @@ -1,3 +1,16 @@ +//----------------------------------------------------------------------------- +// Data structures and prototypes for slvs.lib, a geometric constraint solver. +// +// See the comments in this file, the accompanying sample code (example.c) +// that uses this library, and the accompanying documentation (DOC.txt). +// +// This code is provide for evaluation purposes only. To purchase a license, +// please visit: +// +// http://solvespace.com/ +// +// Copyright 2009, Jonathan Westhues +//----------------------------------------------------------------------------- #ifndef __SLVS_H #define __SLVS_H @@ -31,6 +44,10 @@ typedef struct { #define SLVS_E_DISTANCE 70000 +// The special point, normal, and distance types used for parametric step +// and repeat, extrude, and assembly are currently not exposed. Please +// contact us if you are interested in using these. + #define SLVS_E_WORKPLANE 80000 #define SLVS_E_LINE_SEGMENT 80001 #define SLVS_E_CUBIC 80002 @@ -142,7 +159,10 @@ typedef struct { // its size in faileds. // // The solver will set faileds equal to the number of problematic - // constraints, and write their Slvs_hConstraints on + // constraints, and write their Slvs_hConstraints into failed[]. To + // ensure that there is sufficient space for any possible set of + // failing constraints, faileds should be greater than or equal to + // constraints. Slvs_hConstraint *failed; int faileds;