Polish a few little things in the constraint solver library stuff.

[git-p4: depot-paths = "//depot/solvespace/": change = 1947]
solver
Jonathan Westhues 2009-04-21 22:15:01 -08:00
parent 9efa922795
commit f8dbc89189
4 changed files with 126 additions and 22 deletions

View File

@ -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.

View File

@ -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;

View File

@ -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;
}

View File

@ -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;