Change how step and repeat works: now I build the union of all the

steps in thisShell or thisMesh, and then let the Boolean proceed as
usual. If everything works, then this is equivalent. And it's less
code, and it makes stuff like stepping the step and repeat work.

Also begin to work on line/entity/constraint styles, but no real
work yet.

[git-p4: depot-paths = "//depot/solvespace/": change = 2018]
This commit is contained in:
Jonathan Westhues 2009-07-19 17:47:59 -08:00
parent 8b7f45e72e
commit 92da6c665b
7 changed files with 97 additions and 80 deletions

View File

@ -18,6 +18,7 @@ SSOBJS = $(OBJDIR)\solvespace.obj \
$(OBJDIR)\graphicswin.obj \ $(OBJDIR)\graphicswin.obj \
$(OBJDIR)\modify.obj \ $(OBJDIR)\modify.obj \
$(OBJDIR)\util.obj \ $(OBJDIR)\util.obj \
$(OBJDIR)\style.obj \
$(OBJDIR)\entity.obj \ $(OBJDIR)\entity.obj \
$(OBJDIR)\drawentity.obj \ $(OBJDIR)\drawentity.obj \
$(OBJDIR)\group.obj \ $(OBJDIR)\group.obj \

View File

@ -103,12 +103,14 @@ const SolveSpace::SaveTable SolveSpace::SAVED[] = {
{ 'r', "Request.workplane.v", 'x', &(SS.sv.r.workplane.v) }, { 'r', "Request.workplane.v", 'x', &(SS.sv.r.workplane.v) },
{ 'r', "Request.group.v", 'x', &(SS.sv.r.group.v) }, { 'r', "Request.group.v", 'x', &(SS.sv.r.group.v) },
{ 'r', "Request.construction", 'b', &(SS.sv.r.construction) }, { 'r', "Request.construction", 'b', &(SS.sv.r.construction) },
{ 'r', "Request.style", 'x', &(SS.sv.r.style) },
{ 'r', "Request.str", 'N', &(SS.sv.r.str) }, { 'r', "Request.str", 'N', &(SS.sv.r.str) },
{ 'r', "Request.font", 'N', &(SS.sv.r.font) }, { 'r', "Request.font", 'N', &(SS.sv.r.font) },
{ 'e', "Entity.h.v", 'x', &(SS.sv.e.h.v) }, { 'e', "Entity.h.v", 'x', &(SS.sv.e.h.v) },
{ 'e', "Entity.type", 'd', &(SS.sv.e.type) }, { 'e', "Entity.type", 'd', &(SS.sv.e.type) },
{ 'e', "Entity.construction", 'b', &(SS.sv.e.construction) }, { 'e', "Entity.construction", 'b', &(SS.sv.e.construction) },
{ 'e', "Entity.style", 'x', &(SS.sv.e.style) },
{ 'e', "Entity.str", 'N', &(SS.sv.e.str) }, { 'e', "Entity.str", 'N', &(SS.sv.e.str) },
{ 'e', "Entity.font", 'N', &(SS.sv.e.font) }, { 'e', "Entity.font", 'N', &(SS.sv.e.font) },
{ 'e', "Entity.point[0].v", 'x', &(SS.sv.e.point[0].v) }, { 'e', "Entity.point[0].v", 'x', &(SS.sv.e.point[0].v) },
@ -146,6 +148,7 @@ const SolveSpace::SaveTable SolveSpace::SAVED[] = {
{ 'c', "Constraint.disp.offset.x", 'f', &(SS.sv.c.disp.offset.x) }, { '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.y", 'f', &(SS.sv.c.disp.offset.y) },
{ 'c', "Constraint.disp.offset.z", 'f', &(SS.sv.c.disp.offset.z) }, { 'c', "Constraint.disp.offset.z", 'f', &(SS.sv.c.disp.offset.z) },
{ 'c', "Constraint.disp.style", 'x', &(SS.sv.c.disp.style) },
{ 0, NULL, NULL, NULL }, { 0, NULL, NULL, NULL },
}; };

View File

@ -75,12 +75,11 @@ void SMesh::RemapFaces(Group *g, int remap) {
} }
template<class T> template<class T>
void Group::GenerateForStepAndRepeat(T *prevs, T *steps, T *outs, int how) { void Group::GenerateForStepAndRepeat(T *steps, T *outs) {
T workA, workB; T workA, workB;
ZERO(&workA); ZERO(&workA);
ZERO(&workB); ZERO(&workB);
T *soFar = &workA, *scratch = &workB; T *soFar = &workA, *scratch = &workB;
soFar->MakeFromCopyOf(prevs);
int n = (int)valA, a0 = 0; int n = (int)valA, a0 = 0;
if(subtype == ONE_SIDED && skipFirst) { if(subtype == ONE_SIDED && skipFirst) {
@ -111,15 +110,14 @@ void Group::GenerateForStepAndRepeat(T *prevs, T *steps, T *outs, int how) {
// We need to rewrite any plane face entities to the transformed ones. // We need to rewrite any plane face entities to the transformed ones.
transd.RemapFaces(this, remap); transd.RemapFaces(this, remap);
if(how == COMBINE_AS_DIFFERENCE) { // And tack this transformed copy on to the return.
scratch->MakeFromDifferenceOf(soFar, &transd); if(soFar->IsEmpty()) {
} else if(how == COMBINE_AS_UNION) { scratch->MakeFromCopyOf(&transd);
scratch->MakeFromUnionOf(soFar, &transd);
} else { } else {
scratch->MakeFromAssemblyOf(soFar, &transd); scratch->MakeFromUnionOf(soFar, &transd);
} }
SWAP(T *, scratch, soFar);
SWAP(T *, scratch, soFar);
scratch->Clear(); scratch->Clear();
transd.Clear(); transd.Clear();
} }
@ -129,7 +127,7 @@ void Group::GenerateForStepAndRepeat(T *prevs, T *steps, T *outs, int how) {
} }
template<class T> template<class T>
void Group::GenerateForBoolean(T *prevs, T *thiss, T *outs) { void Group::GenerateForBoolean(T *prevs, T *thiss, T *outs, int how) {
// If this group contributes no new mesh, then our running mesh is the // If this group contributes no new mesh, then our running mesh is the
// same as last time, no combining required. Likewise if we have a mesh // same as last time, no combining required. Likewise if we have a mesh
// but it's suppressed. // but it's suppressed.
@ -140,9 +138,9 @@ void Group::GenerateForBoolean(T *prevs, T *thiss, T *outs) {
// So our group's shell appears in thisShell. Combine this with the // So our group's shell appears in thisShell. Combine this with the
// previous group's shell, using the requested operation. // previous group's shell, using the requested operation.
if(meshCombine == COMBINE_AS_UNION) { if(how == COMBINE_AS_UNION) {
outs->MakeFromUnionOf(prevs, thiss); outs->MakeFromUnionOf(prevs, thiss);
} else if(meshCombine == COMBINE_AS_DIFFERENCE) { } else if(how == COMBINE_AS_DIFFERENCE) {
outs->MakeFromDifferenceOf(prevs, thiss); outs->MakeFromDifferenceOf(prevs, thiss);
} else { } else {
outs->MakeFromAssemblyOf(prevs, thiss); outs->MakeFromAssemblyOf(prevs, thiss);
@ -153,63 +151,21 @@ void Group::GenerateShellAndMesh(void) {
bool prevBooleanFailed = booleanFailed; bool prevBooleanFailed = booleanFailed;
booleanFailed = false; booleanFailed = false;
Group *srcg = this;
thisShell.Clear(); thisShell.Clear();
thisMesh.Clear(); thisMesh.Clear();
runningShell.Clear(); runningShell.Clear();
runningMesh.Clear(); runningMesh.Clear();
if(type == TRANSLATE || type == ROTATE) { if(type == TRANSLATE || type == ROTATE) {
Group *src = SK.GetGroup(opA); // A step and repeat gets merged against the group's prevous group,
Group *pg = src->PreviousGroup(); // not our own previous group.
srcg = SK.GetGroup(opA);
if(src->thisMesh.IsEmpty() && pg->runningMesh.IsEmpty() && !forceToMesh) GenerateForStepAndRepeat<SShell>(&(srcg->thisShell), &thisShell);
{ GenerateForStepAndRepeat<SMesh> (&(srcg->thisMesh), &thisMesh);
SShell *toStep = &(src->thisShell), } else if(type == EXTRUDE) {
*prev = &(pg->runningShell);
// This isn't used, but it makes sure the display and calculation
// of our shell doesn't get optimized out because it looks like
// we contribute no solid model.
thisShell.MakeFromCopyOf(toStep);
GenerateForStepAndRepeat<SShell>
(prev, toStep, &runningShell, src->meshCombine);
if(meshCombine != COMBINE_AS_ASSEMBLE) {
runningShell.MergeCoincidentSurfaces();
}
} else {
SMesh prevm, stepm;
ZERO(&prevm);
ZERO(&stepm);
prevm.MakeFromCopyOf(&(pg->runningMesh));
pg->runningShell.TriangulateInto(&prevm);
// Setting thisMesh for same reasons as thisShell above.
thisMesh.MakeFromCopyOf(&prevm);
stepm.MakeFromCopyOf(&(src->thisMesh));
src->thisShell.TriangulateInto(&stepm);
SMesh outm;
ZERO(&outm);
GenerateForStepAndRepeat<SMesh>
(&prevm, &stepm, &outm, src->meshCombine);
// And make sure that the output mesh is vertex-to-vertex.
SKdNode *root = SKdNode::From(&outm);
root->SnapToMesh(&outm);
root->MakeMeshInto(&runningMesh);
outm.Clear();
stepm.Clear();
prevm.Clear();
}
displayDirty = true;
return;
}
if(type == EXTRUDE) {
Group *src = SK.GetGroup(opA); Group *src = SK.GetGroup(opA);
Vector translate = Vector::From(h.param(0), h.param(1), h.param(2)); Vector translate = Vector::From(h.param(0), h.param(1), h.param(2));
@ -298,7 +254,7 @@ void Group::GenerateShellAndMesh(void) {
thisShell.RemapFaces(this, 0); thisShell.RemapFaces(this, 0);
} }
if(meshCombine != COMBINE_AS_ASSEMBLE) { if(srcg->meshCombine != COMBINE_AS_ASSEMBLE) {
thisShell.MergeCoincidentSurfaces(); thisShell.MergeCoincidentSurfaces();
} }
@ -306,12 +262,14 @@ void Group::GenerateShellAndMesh(void) {
// the previous group's mesh or shell with the requested Boolean, and // the previous group's mesh or shell with the requested Boolean, and
// we're done. // we're done.
Group *pg = PreviousGroup(); Group *prevg = srcg->RunningMeshGroup();
if(pg->runningMesh.IsEmpty() && thisMesh.IsEmpty() && !forceToMesh) {
SShell *prevs = &(pg->runningShell);
GenerateForBoolean<SShell>(prevs, &thisShell, &runningShell);
if(meshCombine != COMBINE_AS_ASSEMBLE) { if(prevg->runningMesh.IsEmpty() && thisMesh.IsEmpty() && !forceToMesh) {
SShell *prevs = &(prevg->runningShell);
GenerateForBoolean<SShell>(prevs, &thisShell, &runningShell,
srcg->meshCombine);
if(srcg->meshCombine != COMBINE_AS_ASSEMBLE) {
runningShell.MergeCoincidentSurfaces(); runningShell.MergeCoincidentSurfaces();
} }
@ -326,15 +284,15 @@ void Group::GenerateShellAndMesh(void) {
ZERO(&prevm); ZERO(&prevm);
ZERO(&thism); ZERO(&thism);
prevm.MakeFromCopyOf(&(pg->runningMesh)); prevm.MakeFromCopyOf(&(prevg->runningMesh));
pg->runningShell.TriangulateInto(&prevm); prevg->runningShell.TriangulateInto(&prevm);
thism.MakeFromCopyOf(&thisMesh); thism.MakeFromCopyOf(&thisMesh);
thisShell.TriangulateInto(&thism); thisShell.TriangulateInto(&thism);
SMesh outm; SMesh outm;
ZERO(&outm); ZERO(&outm);
GenerateForBoolean<SMesh>(&prevm, &thism, &outm); GenerateForBoolean<SMesh>(&prevm, &thism, &outm, srcg->meshCombine);
// And make sure that the output mesh is vertex-to-vertex. // And make sure that the output mesh is vertex-to-vertex.
SKdNode *root = SKdNode::From(&outm); SKdNode *root = SKdNode::From(&outm);
@ -387,6 +345,14 @@ Group *Group::PreviousGroup(void) {
return &(SK.group.elem[i-1]); return &(SK.group.elem[i-1]);
} }
Group *Group::RunningMeshGroup(void) {
if(type == TRANSLATE || type == ROTATE) {
return SK.GetGroup(opA)->RunningMeshGroup();
} else {
return PreviousGroup();
}
}
void Group::DrawDisplayItems(int t) { void Group::DrawDisplayItems(int t) {
int specColor; int specColor;
if(t == DRAWING_3D || t == DRAWING_WORKPLANE) { if(t == DRAWING_3D || t == DRAWING_WORKPLANE) {
@ -432,7 +398,7 @@ void Group::Draw(void) {
// can control this stuff independently, with show/hide solids, edges, // can control this stuff independently, with show/hide solids, edges,
// mesh, etc. // mesh, etc.
Group *pg = PreviousGroup(); Group *pg = RunningMeshGroup();
if(pg && thisMesh.IsEmpty() && thisShell.IsEmpty()) { if(pg && thisMesh.IsEmpty() && thisShell.IsEmpty()) {
// We don't contribute any new solid model in this group, so our // We don't contribute any new solid model in this group, so our
// display items are identical to the previous group's; which means // display items are identical to the previous group's; which means

View File

@ -6,14 +6,15 @@ class hGroup;
class hRequest; class hRequest;
class hEntity; class hEntity;
class hParam; class hParam;
class hStyle;
class hConstraint;
class hEquation;
class Entity; class Entity;
class Param; class Param;
class hConstraint;
class hEquation;
class Equation; class Equation;
// All of the hWhatever handles are a 32-bit ID, that is used to represent // All of the hWhatever handles are a 32-bit ID, that is used to represent
// some data structure in the sketch. // some data structure in the sketch.
class hGroup { class hGroup {
@ -55,6 +56,11 @@ public:
inline hRequest request(void); inline hRequest request(void);
}; };
class hStyle {
public:
DWORD v;
};
class EntityId { class EntityId {
public: public:
@ -210,9 +216,10 @@ public:
void GenerateLoops(void); void GenerateLoops(void);
// And the mesh stuff // And the mesh stuff
Group *PreviousGroup(void); Group *PreviousGroup(void);
Group *RunningMeshGroup(void);
void GenerateShellAndMesh(void); void GenerateShellAndMesh(void);
template<class T> void GenerateForStepAndRepeat(T *a, T *b, T *o, int how); template<class T> void GenerateForStepAndRepeat(T *steps, T *outs);
template<class T> void GenerateForBoolean(T *a, T *b, T *o); template<class T> void GenerateForBoolean(T *a, T *b, T *o, int how);
void GenerateDisplayItems(void); void GenerateDisplayItems(void);
void DrawDisplayItems(int t); void DrawDisplayItems(int t);
void Draw(void); void Draw(void);
@ -247,6 +254,7 @@ public:
hEntity workplane; // or Entity::FREE_IN_3D hEntity workplane; // or Entity::FREE_IN_3D
hGroup group; hGroup group;
hStyle style;
bool construction; bool construction;
NameStr str; NameStr str;
@ -395,6 +403,7 @@ public:
// and the shown state also gets saved here, for later import // and the shown state also gets saved here, for later import
bool actVisible; bool actVisible;
hStyle style;
bool construction; bool construction;
// Routines to draw and hit-test the representation of the entity // Routines to draw and hit-test the representation of the entity
@ -523,6 +532,7 @@ public:
// These define how the constraint is drawn on-screen. // These define how the constraint is drawn on-screen.
struct { struct {
Vector offset; Vector offset;
hStyle style;
} disp; } disp;
// State for drawing or getting distance (for hit testing). // State for drawing or getting distance (for hit testing).
@ -583,6 +593,32 @@ public:
}; };
class Style {
int tag;
hStyle h;
static const int ACTIVE = 1;
static const int CONSTRUCTION = 2;
static const int INACTIVE = 3;
static const int DATUM = 4;
static const int SOLID_EDGE = 5;
static const int CONSTRAINT = 6;
static const int SELECTED = 7;
static const int HOVERED = 8;
static const int FIRST_CUSTOM = 0x1000;
static const int WIDTH_ABSOLUTE = 0;
static const int WIDTH_RELATIVE = 1;
static const int WIDTH_PIXELS = 2;
double width;
int widthHow;
DWORD color;
bool visible;
bool exportable;
};
inline hEntity hGroup::entity(int i) inline hEntity hGroup::entity(int i)
{ hEntity r; r.v = 0x80000000 | (v << 16) | i; return r; } { hEntity r; r.v = 0x80000000 | (v << 16) | i; return r; }
inline hParam hGroup::param(int i) inline hParam hGroup::param(int i)

5
style.cpp Normal file
View File

@ -0,0 +1,5 @@
#include "solvespace.h"
//DWORD Style::Color(hStyle h) {
//}

View File

@ -518,7 +518,7 @@ Vector Vector::WithMagnitude(double v) {
if(m == 0) { if(m == 0) {
// We can do a zero vector with zero magnitude, but not any other cases. // We can do a zero vector with zero magnitude, but not any other cases.
if(fabs(v) > 1e-100) { if(fabs(v) > 1e-100) {
dbp("Vector::WithMagnitude of zero vector!"); dbp("Vector::WithMagnitude(%g) of zero vector!", v);
} }
return From(0, 0, 0); return From(0, 0, 0);
} else { } else {

View File

@ -1,12 +1,18 @@
grid grid
associative entities from solid model, as a special group line styles (color, thickness)
rounding, as a special group margins in exported vector art
background color setting
better text
better drawing of dimensions
faster triangulation
SpaceNavigator support
----- -----
line styles (color, thickness)
loop detection loop detection
IGES export IGES export
incremental regen of entities incremental regen of entities
associative entities from solid model, as a special group
rounding, as a special group