
vectors", represented by unit quaternions. This permits me to add circles, where the normal defines the plane of the circle. Still many things painful. The interface for editing normals is not so intuitive, and it's not yet clear how I would e.g. export a circle entity and recreate it properly, since that entity has a param not associated with a normal or point. And the transformed points/normals do not yet support rotations. That will be necessary soon. [git-p4: depot-paths = "//depot/solvespace/": change = 1705]
279 lines
10 KiB
C++
279 lines
10 KiB
C++
#include "solvespace.h"
|
||
|
||
void SolveSpace::NewFile(void) {
|
||
constraint.Clear();
|
||
request.Clear();
|
||
group.Clear();
|
||
|
||
entity.Clear();
|
||
param.Clear();
|
||
|
||
// Our initial group, that contains the references.
|
||
Group g;
|
||
memset(&g, 0, sizeof(g));
|
||
g.visible = true;
|
||
g.name.strcpy("#references");
|
||
g.type = Group::DRAWING;
|
||
g.h = Group::HGROUP_REFERENCES;
|
||
group.Add(&g);
|
||
|
||
// And an empty group, for the first stuff the user draws.
|
||
g.name.strcpy("drawing");
|
||
group.AddAndAssignId(&g);
|
||
|
||
|
||
// Let's create three two-d coordinate systems, for the coordinate
|
||
// planes; these are our references, present in every sketch.
|
||
Request r;
|
||
memset(&r, 0, sizeof(r));
|
||
r.type = Request::WORKPLANE;
|
||
r.group = Group::HGROUP_REFERENCES;
|
||
r.workplane = Entity::FREE_IN_3D;
|
||
|
||
r.name.strcpy("#XY");
|
||
r.h = Request::HREQUEST_REFERENCE_XY;
|
||
request.Add(&r);
|
||
|
||
r.name.strcpy("#YZ");
|
||
r.h = Request::HREQUEST_REFERENCE_YZ;
|
||
request.Add(&r);
|
||
|
||
r.name.strcpy("#ZX");
|
||
r.h = Request::HREQUEST_REFERENCE_ZX;
|
||
request.Add(&r);
|
||
}
|
||
|
||
|
||
const SolveSpace::SaveTable SolveSpace::SAVED[] = {
|
||
{ 'g', "Group.h.v", 'x', &(SS.sv.g.h.v) },
|
||
{ 'g', "Group.type", 'd', &(SS.sv.g.type) },
|
||
{ 'g', "Group.name", 'N', &(SS.sv.g.name) },
|
||
{ 'g', "Group.opA.v", 'x', &(SS.sv.g.opA.v) },
|
||
{ 'g', "Group.opB.v", 'x', &(SS.sv.g.opB.v) },
|
||
{ 'g', "Group.solveOrder", 'd', &(SS.sv.g.solveOrder) },
|
||
{ 'g', "Group.visible", 'b', &(SS.sv.g.visible) },
|
||
{ 'g', "Group.remap", 'M', &(SS.sv.g.remap) },
|
||
|
||
{ 'p', "Param.h.v.", 'x', &(SS.sv.p.h.v) },
|
||
{ 'p', "Param.val", 'f', &(SS.sv.p.val) },
|
||
|
||
{ 'r', "Request.h.v", 'x', &(SS.sv.r.h.v) },
|
||
{ 'r', "Request.type", 'd', &(SS.sv.r.type) },
|
||
{ 'r', "Request.workplane.v", 'x', &(SS.sv.r.workplane.v) },
|
||
{ 'r', "Request.group.v", 'x', &(SS.sv.r.group.v) },
|
||
{ 'r', "Request.name", 'N', &(SS.sv.r.name) },
|
||
{ 'r', "Request.construction", 'b', &(SS.sv.r.construction) },
|
||
|
||
{ 'e', "Entity.h.v", 'x', &(SS.sv.e.h.v) },
|
||
{ 'e', "Entity.type", 'd', &(SS.sv.e.type) },
|
||
{ 'e', "Entity.group.v", 'x', &(SS.sv.e.group.v) },
|
||
{ 'e', "Entity.param[0].v", 'x', &(SS.sv.e.param[0].v) },
|
||
{ 'e', "Entity.param[1].v", 'x', &(SS.sv.e.param[1].v) },
|
||
{ 'e', "Entity.param[2].v", 'x', &(SS.sv.e.param[2].v) },
|
||
{ 'e', "Entity.param[3].v", 'x', &(SS.sv.e.param[3].v) },
|
||
{ 'e', "Entity.point[0].v", 'x', &(SS.sv.e.point[0].v) },
|
||
{ 'e', "Entity.point[1].v", 'x', &(SS.sv.e.point[1].v) },
|
||
{ 'e', "Entity.point[2].v", 'x', &(SS.sv.e.point[2].v) },
|
||
{ 'e', "Entity.point[3].v", 'x', &(SS.sv.e.point[3].v) },
|
||
{ 'e', "Entity.normal.v", 'x', &(SS.sv.e.normal.v) },
|
||
{ 'e', "Entity.workplane.v", 'x', &(SS.sv.e.workplane.v) },
|
||
{ 'e', "Entity.numPoint.x", 'f', &(SS.sv.e.numPoint.x) },
|
||
{ 'e', "Entity.numPoint.y", 'f', &(SS.sv.e.numPoint.y) },
|
||
{ 'e', "Entity.numPoint.z", 'f', &(SS.sv.e.numPoint.z) },
|
||
{ 'e', "Entity.numNormal.w", 'f', &(SS.sv.e.numNormal.w) },
|
||
{ 'e', "Entity.numNormal.vx", 'f', &(SS.sv.e.numNormal.vx) },
|
||
{ 'e', "Entity.numNormal.vy", 'f', &(SS.sv.e.numNormal.vy) },
|
||
{ 'e', "Entity.numNormal.vz", 'f', &(SS.sv.e.numNormal.vz) },
|
||
|
||
{ 'c', "Constraint.h.v", 'x', &(SS.sv.c.h.v) },
|
||
{ 'c', "Constraint.type", 'd', &(SS.sv.c.type) },
|
||
{ 'c', "Constraint.group.v", 'x', &(SS.sv.c.group.v) },
|
||
{ 'c', "Constraint.workplane.v", 'x', &(SS.sv.c.workplane.v) },
|
||
{ 'c', "Constraint.exprA", 'E', &(SS.sv.c.exprA) },
|
||
{ 'c', "Constraint.exprB", 'E', &(SS.sv.c.exprB) },
|
||
{ 'c', "Constraint.ptA.v", 'x', &(SS.sv.c.ptA.v) },
|
||
{ 'c', "Constraint.ptB.v", 'x', &(SS.sv.c.ptB.v) },
|
||
{ 'c', "Constraint.ptC.v", 'x', &(SS.sv.c.ptC.v) },
|
||
{ 'c', "Constraint.entityA.v", 'x', &(SS.sv.c.entityA.v) },
|
||
{ 'c', "Constraint.entityB.v", 'x', &(SS.sv.c.entityB.v) },
|
||
{ 'c', "Constraint.disp.offset.x", 'f', &(SS.sv.c.disp.offset.x)},
|
||
{ 'c', "Constraint.disp.offset.y", 'f', &(SS.sv.c.disp.offset.y)},
|
||
{ 'c', "Constraint.disp.offset.z", 'f', &(SS.sv.c.disp.offset.z)},
|
||
|
||
{ 0, NULL, NULL, NULL },
|
||
};
|
||
|
||
void SolveSpace::SaveUsingTable(int type) {
|
||
int i;
|
||
for(i = 0; SAVED[i].type != 0; i++) {
|
||
if(SAVED[i].type != type) continue;
|
||
fprintf(fh, "%s=", SAVED[i].desc);
|
||
void *p = SAVED[i].ptr;
|
||
switch(SAVED[i].fmt) {
|
||
case 'd': fprintf(fh, "%d", *((int *)p)); break;
|
||
case 'b': fprintf(fh, "%d", *((bool *)p) ? 1 : 0); break;
|
||
case 'x': fprintf(fh, "%08x", *((DWORD *)p)); break;
|
||
case 'f': fprintf(fh, "%.20f", *((double *)p)); break;
|
||
case 'N': fprintf(fh, "%s", ((NameStr *)p)->str); break;
|
||
case 'E': fprintf(fh, "%s", (*((Expr **)p))->Print()); break;
|
||
|
||
case 'M': {
|
||
int j;
|
||
fprintf(fh, "{\n");
|
||
IdList<EntityMap,EntityId> *m = (IdList<EntityMap,EntityId> *)p;
|
||
for(j = 0; j < m->n; j++) {
|
||
EntityMap *em = &(m->elem[j]);
|
||
fprintf(fh, " %d %08x %d\n",
|
||
em->h.v, em->input.v, em->copyNumber);
|
||
}
|
||
fprintf(fh, "}");
|
||
break;
|
||
}
|
||
|
||
default: oops();
|
||
}
|
||
fprintf(fh, "\n");
|
||
}
|
||
}
|
||
|
||
bool SolveSpace::SaveToFile(char *filename) {
|
||
fh = fopen(filename, "w");
|
||
if(!fh) {
|
||
Error("Couldn't write to file '%s'", filename);
|
||
return false;
|
||
}
|
||
|
||
fprintf(fh, "<EFBFBD><EFBFBD><EFBFBD><EFBFBD>SolveSpaceREVa\n\n\n");
|
||
|
||
int i;
|
||
for(i = 0; i < group.n; i++) {
|
||
sv.g = group.elem[i];
|
||
SaveUsingTable('g');
|
||
fprintf(fh, "AddGroup\n\n");
|
||
}
|
||
|
||
for(i = 0; i < param.n; i++) {
|
||
sv.p = param.elem[i];
|
||
SaveUsingTable('p');
|
||
fprintf(fh, "AddParam\n\n");
|
||
}
|
||
|
||
for(i = 0; i < request.n; i++) {
|
||
sv.r = request.elem[i];
|
||
SaveUsingTable('r');
|
||
fprintf(fh, "AddRequest\n\n");
|
||
}
|
||
|
||
for(i = 0; i < entity.n; i++) {
|
||
sv.e = entity.elem[i];
|
||
SaveUsingTable('e');
|
||
fprintf(fh, "AddEntity\n\n");
|
||
}
|
||
|
||
for(i = 0; i < constraint.n; i++) {
|
||
sv.c = constraint.elem[i];
|
||
SaveUsingTable('c');
|
||
fprintf(fh, "AddConstraint\n\n");
|
||
}
|
||
|
||
fclose(fh);
|
||
|
||
return true;
|
||
}
|
||
|
||
void SolveSpace::LoadUsingTable(char *key, char *val) {
|
||
int i;
|
||
for(i = 0; SAVED[i].type != 0; i++) {
|
||
if(strcmp(SAVED[i].desc, key)==0) {
|
||
void *p = SAVED[i].ptr;
|
||
switch(SAVED[i].fmt) {
|
||
case 'd': *((int *)p) = atoi(val); break;
|
||
case 'b': *((bool *)p) = (atoi(val) != 0); break;
|
||
case 'x': sscanf(val, "%x", (DWORD *)p); break;
|
||
case 'f': *((double *)p) = atof(val); break;
|
||
case 'N': ((NameStr *)p)->strcpy(val); break;
|
||
case 'E':
|
||
Expr *e;
|
||
e = Expr::FromString(val);
|
||
if(!e) e = Expr::FromConstant(0);
|
||
*((Expr **)p) = e->DeepCopyKeep();
|
||
break;
|
||
|
||
case 'M': {
|
||
IdList<EntityMap,EntityId> *m =
|
||
(IdList<EntityMap,EntityId> *)p;
|
||
m->Clear();
|
||
for(;;) {
|
||
EntityMap em;
|
||
char line2[1024];
|
||
fgets(line2, sizeof(line2), fh);
|
||
if(sscanf(line2, "%d %x %d", &(em.h.v), &(em.input.v),
|
||
&(em.copyNumber)) == 3)
|
||
{
|
||
m->Add(&em);
|
||
} else {
|
||
break;
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
|
||
default: oops();
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
if(SAVED[i].type == 0) oops();
|
||
}
|
||
|
||
bool SolveSpace::LoadFromFile(char *filename) {
|
||
fh = fopen(filename, "r");
|
||
if(!fh) {
|
||
Error("Couldn't read from file '%s'", filename);
|
||
return false;
|
||
}
|
||
|
||
constraint.Clear();
|
||
request.Clear();
|
||
group.Clear();
|
||
|
||
entity.Clear();
|
||
param.Clear();
|
||
|
||
char line[1024];
|
||
while(fgets(line, sizeof(line), fh)) {
|
||
char *s = strchr(line, '\n');
|
||
if(s) *s = '\0';
|
||
|
||
if(*line == '\0') continue;
|
||
|
||
char *e = strchr(line, '=');
|
||
if(e) {
|
||
*e = '\0';
|
||
char *key = line, *val = e+1;
|
||
LoadUsingTable(key, val);
|
||
} else if(strcmp(line, "AddGroup")==0) {
|
||
SS.group.Add(&(sv.g));
|
||
} else if(strcmp(line, "AddParam")==0) {
|
||
// params are regenerated, but we want to preload the values
|
||
// for initial guesses
|
||
SS.param.Add(&(sv.p));
|
||
} else if(strcmp(line, "AddEntity")==0) {
|
||
// entities are regenerated
|
||
} else if(strcmp(line, "AddRequest")==0) {
|
||
SS.request.Add(&(sv.r));
|
||
} else if(strcmp(line, "AddConstraint")==0) {
|
||
SS.constraint.Add(&(sv.c));
|
||
} else if(strcmp(line, "<EFBFBD><EFBFBD><EFBFBD><EFBFBD>SolveSpaceREVa")==0) {
|
||
// do nothing, version string
|
||
} else {
|
||
oops();
|
||
}
|
||
}
|
||
|
||
fclose(fh);
|
||
|
||
return true;
|
||
}
|
||
|