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)\modify.obj \
$(OBJDIR)\util.obj \
$(OBJDIR)\style.obj \
$(OBJDIR)\entity.obj \
$(OBJDIR)\drawentity.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.group.v", 'x', &(SS.sv.r.group.v) },
{ '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.font", 'N', &(SS.sv.r.font) },
{ 'e', "Entity.h.v", 'x', &(SS.sv.e.h.v) },
{ 'e', "Entity.type", 'd', &(SS.sv.e.type) },
{ '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.font", 'N', &(SS.sv.e.font) },
{ '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.y", 'f', &(SS.sv.c.disp.offset.y) },
{ '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 },
};

View File

@ -75,12 +75,11 @@ void SMesh::RemapFaces(Group *g, int remap) {
}
template<class T>
void Group::GenerateForStepAndRepeat(T *prevs, T *steps, T *outs, int how) {
void Group::GenerateForStepAndRepeat(T *steps, T *outs) {
T workA, workB;
ZERO(&workA);
ZERO(&workB);
T *soFar = &workA, *scratch = &workB;
soFar->MakeFromCopyOf(prevs);
int n = (int)valA, a0 = 0;
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.
transd.RemapFaces(this, remap);
if(how == COMBINE_AS_DIFFERENCE) {
scratch->MakeFromDifferenceOf(soFar, &transd);
} else if(how == COMBINE_AS_UNION) {
scratch->MakeFromUnionOf(soFar, &transd);
// And tack this transformed copy on to the return.
if(soFar->IsEmpty()) {
scratch->MakeFromCopyOf(&transd);
} else {
scratch->MakeFromAssemblyOf(soFar, &transd);
scratch->MakeFromUnionOf(soFar, &transd);
}
SWAP(T *, scratch, soFar);
SWAP(T *, scratch, soFar);
scratch->Clear();
transd.Clear();
}
@ -129,7 +127,7 @@ void Group::GenerateForStepAndRepeat(T *prevs, T *steps, T *outs, int how) {
}
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
// same as last time, no combining required. Likewise if we have a mesh
// 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
// previous group's shell, using the requested operation.
if(meshCombine == COMBINE_AS_UNION) {
if(how == COMBINE_AS_UNION) {
outs->MakeFromUnionOf(prevs, thiss);
} else if(meshCombine == COMBINE_AS_DIFFERENCE) {
} else if(how == COMBINE_AS_DIFFERENCE) {
outs->MakeFromDifferenceOf(prevs, thiss);
} else {
outs->MakeFromAssemblyOf(prevs, thiss);
@ -153,63 +151,21 @@ void Group::GenerateShellAndMesh(void) {
bool prevBooleanFailed = booleanFailed;
booleanFailed = false;
Group *srcg = this;
thisShell.Clear();
thisMesh.Clear();
runningShell.Clear();
runningMesh.Clear();
if(type == TRANSLATE || type == ROTATE) {
Group *src = SK.GetGroup(opA);
Group *pg = src->PreviousGroup();
// A step and repeat gets merged against the group's prevous group,
// not our own previous group.
srcg = SK.GetGroup(opA);
if(src->thisMesh.IsEmpty() && pg->runningMesh.IsEmpty() && !forceToMesh)
{
SShell *toStep = &(src->thisShell),
*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) {
GenerateForStepAndRepeat<SShell>(&(srcg->thisShell), &thisShell);
GenerateForStepAndRepeat<SMesh> (&(srcg->thisMesh), &thisMesh);
} else if(type == EXTRUDE) {
Group *src = SK.GetGroup(opA);
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);
}
if(meshCombine != COMBINE_AS_ASSEMBLE) {
if(srcg->meshCombine != COMBINE_AS_ASSEMBLE) {
thisShell.MergeCoincidentSurfaces();
}
@ -306,12 +262,14 @@ void Group::GenerateShellAndMesh(void) {
// the previous group's mesh or shell with the requested Boolean, and
// we're done.
Group *pg = PreviousGroup();
if(pg->runningMesh.IsEmpty() && thisMesh.IsEmpty() && !forceToMesh) {
SShell *prevs = &(pg->runningShell);
GenerateForBoolean<SShell>(prevs, &thisShell, &runningShell);
Group *prevg = srcg->RunningMeshGroup();
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();
}
@ -326,15 +284,15 @@ void Group::GenerateShellAndMesh(void) {
ZERO(&prevm);
ZERO(&thism);
prevm.MakeFromCopyOf(&(pg->runningMesh));
pg->runningShell.TriangulateInto(&prevm);
prevm.MakeFromCopyOf(&(prevg->runningMesh));
prevg->runningShell.TriangulateInto(&prevm);
thism.MakeFromCopyOf(&thisMesh);
thisShell.TriangulateInto(&thism);
SMesh 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.
SKdNode *root = SKdNode::From(&outm);
@ -387,6 +345,14 @@ Group *Group::PreviousGroup(void) {
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) {
int specColor;
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,
// mesh, etc.
Group *pg = PreviousGroup();
Group *pg = RunningMeshGroup();
if(pg && thisMesh.IsEmpty() && thisShell.IsEmpty()) {
// We don't contribute any new solid model in this group, so our
// display items are identical to the previous group's; which means

View File

@ -6,14 +6,15 @@ class hGroup;
class hRequest;
class hEntity;
class hParam;
class hStyle;
class hConstraint;
class hEquation;
class Entity;
class Param;
class hConstraint;
class hEquation;
class Equation;
// All of the hWhatever handles are a 32-bit ID, that is used to represent
// some data structure in the sketch.
class hGroup {
@ -55,6 +56,11 @@ public:
inline hRequest request(void);
};
class hStyle {
public:
DWORD v;
};
class EntityId {
public:
@ -210,9 +216,10 @@ public:
void GenerateLoops(void);
// And the mesh stuff
Group *PreviousGroup(void);
Group *RunningMeshGroup(void);
void GenerateShellAndMesh(void);
template<class T> void GenerateForStepAndRepeat(T *a, T *b, T *o, int how);
template<class T> void GenerateForBoolean(T *a, T *b, T *o);
template<class T> void GenerateForStepAndRepeat(T *steps, T *outs);
template<class T> void GenerateForBoolean(T *a, T *b, T *o, int how);
void GenerateDisplayItems(void);
void DrawDisplayItems(int t);
void Draw(void);
@ -247,6 +254,7 @@ public:
hEntity workplane; // or Entity::FREE_IN_3D
hGroup group;
hStyle style;
bool construction;
NameStr str;
@ -395,6 +403,7 @@ public:
// and the shown state also gets saved here, for later import
bool actVisible;
hStyle style;
bool construction;
// 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.
struct {
Vector offset;
hStyle style;
} disp;
// 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)
{ hEntity r; r.v = 0x80000000 | (v << 16) | i; return r; }
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) {
// We can do a zero vector with zero magnitude, but not any other cases.
if(fabs(v) > 1e-100) {
dbp("Vector::WithMagnitude of zero vector!");
dbp("Vector::WithMagnitude(%g) of zero vector!", v);
}
return From(0, 0, 0);
} else {

View File

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