Add a convenience command to draw a rectangle (as four line

segments), add the toggle construction command, and color the lines
differently depending on what group you're in.

Also change dynamic memory stuff to use a Win32 heap for everything
(no malloc), and validate that often. I think I've seen it crash,
though I can't reproduce it.

[git-p4: depot-paths = "//depot/solvespace/": change = 1708]
This commit is contained in:
Jonathan Westhues 2008-05-06 20:17:29 -08:00
parent c767d55c71
commit 6b264a6ba6
11 changed files with 119 additions and 17 deletions

View File

@ -18,12 +18,23 @@ void Constraint::ConstrainCoincident(hEntity ptA, hEntity ptB) {
memset(&c, 0, sizeof(c));
c.group = SS.GW.activeGroup;
c.workplane = SS.GW.activeWorkplane;
c.type = Constraint::POINTS_COINCIDENT;
c.type = POINTS_COINCIDENT;
c.ptA = ptA;
c.ptB = ptB;
AddConstraint(&c);
}
void Constraint::ConstrainHorizVert(bool horiz, hEntity ls) {
Constraint c;
memset(&c, 0, sizeof(c));
c.group = SS.GW.activeGroup;
c.workplane = SS.GW.activeWorkplane;
if(c.workplane.v == Entity::FREE_IN_3D.v) oops();
c.type = (horiz ? HORIZONTAL : VERTICAL);
c.entityA = ls;
AddConstraint(&c);
}
void Constraint::MenuConstrain(int id) {
Constraint c;
memset(&c, 0, sizeof(c));

View File

@ -31,6 +31,8 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
// If the group is hidden, then the constraints are hidden and not
// able to be selected.
if(!(g->visible)) return;
// And likewise if the group is not the active group.
if(g->h.v != SS.GW.activeGroup.v) return;
// Unit vectors that describe our current view of the scene. One pixel
// long, not one actual unit.

2
dsc.h
View File

@ -159,7 +159,7 @@ public:
void Clear(void) {
elemsAllocated = n = 0;
if(elem) free(elem);
if(elem) MemFree(elem);
elem = NULL;
}

View File

@ -288,7 +288,7 @@ void Entity::LineDrawOrGetDistance(Vector a, Vector b) {
void Entity::LineDrawOrGetDistanceOrEdge(Vector a, Vector b) {
LineDrawOrGetDistance(a, b);
if(dogd.edges) {
if(dogd.edges && !construction) {
SEdge edge;
edge.a = a; edge.b = b;
dogd.edges->l.Add(&edge);
@ -325,7 +325,13 @@ void Entity::DrawOrGetDistance(int order) {
// contribute a distance for the selection, but it still generates edges.
if(!(g->visible) && !dogd.edges) return;
glxColor3d(1, 1, 1);
if(group.v != SS.GW.activeGroup.v) {
glxColor3d(0.5, 0.3, 0.0);
} else if(construction) {
glxColor3d(0.1, 0.7, 0.1);
} else {
glxColor3d(1, 1, 1);
}
switch(type) {
case POINT_XFRMD:

View File

@ -67,6 +67,7 @@ const SolveSpace::SaveTable SolveSpace::SAVED[] = {
{ '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.construction", 'b', &(SS.sv.e.construction) },
{ '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) },

View File

@ -65,7 +65,7 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = {
{ 1, "Sym&bolic Variable\tB", 0, 'B', mReq },
{ 1, "&Import From File...\tI", 0, 'I', mReq },
{ 1, NULL, 0, NULL },
{ 1, "To&ggle Construction\tG", 0, 'G', NULL },
{ 1, "To&ggle Construction\tG", MNU_CONSTRUCTION, 'G', mReq },
{ 0, "&Constrain", 0, NULL },
{ 1, "&Distance / Diameter\tShift+D", MNU_DISTANCE_DIA, 'D'|S, mCon },
@ -346,12 +346,27 @@ void GraphicsWindow::MenuRequest(int id) {
case MNU_CUBIC: s = "click first point of cubic segment"; goto c;
case MNU_CIRCLE: s = "click center of circle"; goto c;
case MNU_WORKPLANE: s = "click origin of workplane"; goto c;
case MNU_RECTANGLE: s = "click one corner of rectangular"; goto c;
c:
SS.GW.pending.operation = id;
SS.GW.pending.description = s;
SS.TW.Show();
break;
case MNU_CONSTRUCTION: {
SS.GW.GroupSelection();
int i;
for(i = 0; i < SS.GW.gs.entities; i++) {
hEntity he = SS.GW.gs.entity[i];
if(!he.isFromRequest()) continue;
Request *r = SS.GetRequest(he.request());
r->construction = !(r->construction);
}
SS.GW.ClearSelection();
SS.GenerateAll(SS.GW.solving == GraphicsWindow::SOLVE_ALWAYS);
break;
}
default: oops();
}
}
@ -687,6 +702,27 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
SS.GetEntity(pending.point)->PointForceTo(v);
break;
case MNU_RECTANGLE: {
hRequest lns[4];
int i;
for(i = 0; i < 4; i++) {
lns[i] = AddRequest(Request::LINE_SEGMENT);
}
for(i = 0; i < 4; i++) {
Constraint::ConstrainCoincident(
lns[i].entity(1), lns[(i+1)%4].entity(2));
SS.GetEntity(lns[i].entity(1))->PointForceTo(v);
SS.GetEntity(lns[i].entity(2))->PointForceTo(v);
}
for(i = 0; i < 4; i++) {
Constraint::ConstrainHorizVert((i % 2)==0, lns[i].entity(0));
}
pending.operation = DRAGGING_NEW_POINT;
pending.point = lns[1].entity(2);
pending.description = "click to place other corner of rectangle";
break;
}
case MNU_CIRCLE:
hr = AddRequest(Request::CIRCLE);
SS.GetEntity(hr.entity(1))->PointForceTo(v);

View File

@ -55,15 +55,17 @@ char *Group::DescriptionString(void) {
void Group::Generate(IdList<Entity,hEntity> *entity,
IdList<Param,hParam> *param)
{
Vector gn = (SS.GW.projRight).Cross(SS.GW.projUp);
gn = gn.WithMagnitude(200/SS.GW.scale);
int i;
switch(type) {
case DRAWING:
return;
case EXTRUDE:
AddParam(param, h.param(0), 50);
AddParam(param, h.param(1), 50);
AddParam(param, h.param(2), 50);
AddParam(param, h.param(0), gn.x);
AddParam(param, h.param(1), gn.y);
AddParam(param, h.param(2), gn.z);
for(i = 0; i < entity->n; i++) {
Entity *e = &(entity->elem[i]);
if(e->group.v != opA.v) continue;
@ -138,8 +140,12 @@ void Group::CopyEntity(hEntity in, int a, hParam dx, hParam dy, hParam dz,
if(isExtrusion) {
if(a != 0) oops();
SS.entity.Add(&en);
hEntity np = en.h;
memset(&en, 0, sizeof(en));
en.point[0] = ep->h;
en.point[1] = en.h;
en.point[1] = np;
en.group = h;
en.h = Remap(ep->h, 1);
en.type = Entity::LINE_SEGMENT;
// And then this line segment gets added
@ -160,6 +166,10 @@ void Group::CopyEntity(hEntity in, int a, hParam dx, hParam dy, hParam dz,
}
void Group::MakePolygons(void) {
int i;
for(i = 0; i < faces.n; i++) {
(faces.elem[i]).Clear();
}
faces.Clear();
if(type == DRAWING) {
edges.l.Clear();
@ -332,6 +342,7 @@ void Request::Generate(IdList<Entity,hEntity> *entity,
e.type = et;
e.group = group;
e.workplane = workplane;
e.construction = construction;
e.h = h.entity(0);
// And generate entities for the points

View File

@ -188,10 +188,15 @@ public:
hGroup group;
hEntity workplane; // or Entity::FREE_IN_3D
bool construction;
// For entities that are derived by a transformation, the number of
// times to apply the transformation.
int timesApplied;
bool HasDirection(void);
ExprVector GetDirection(void);
bool IsWorkplane(void);
// The plane is points P such that P dot (xn, yn, zn) - d = 0
void WorkplaneGetPlaneExprs(ExprVector *n, Expr **d);
@ -349,6 +354,7 @@ public:
static ExprVector PointInThreeSpace(hEntity workplane, Expr *u, Expr *v);
static void ConstrainCoincident(hEntity ptA, hEntity ptB);
static void ConstrainHorizVert(bool horiz, hEntity lineSegment);
};
class hEquation {

View File

@ -55,6 +55,7 @@ void FreeAllTemporary(void);
void *MemRealloc(void *p, int n);
void *MemAlloc(int n);
void MemFree(void *p);
void vl(void); // debug function to validate
#include "dsc.h"

1
ui.h
View File

@ -107,6 +107,7 @@ public:
MNU_CIRCLE,
MNU_RECTANGLE,
MNU_CUBIC,
MNU_CONSTRUCTION,
// Group
MNU_GROUP_DRAWING,
MNU_GROUP_EXTRUDE,

View File

@ -62,23 +62,48 @@ void Error(char *str, ...)
// to be sloppy with our memory management, and just free everything at once
// at the end.
//-----------------------------------------------------------------------------
static HANDLE Heap;
static HANDLE Temp;
void *AllocTemporary(int n)
{
Expr *v = (Expr *)HeapAlloc(Heap, HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY, n);
void *v = HeapAlloc(Temp, HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY, n);
if(!v) oops();
memset(v, 0, n);
return v;
}
void FreeAllTemporary(void)
{
if(Heap) HeapDestroy(Heap);
Heap = HeapCreate(HEAP_NO_SERIALIZE, 1024*1024*20, 0);
if(Temp) HeapDestroy(Temp);
Temp = HeapCreate(HEAP_NO_SERIALIZE, 1024*1024*20, 0);
// This is a good place to validate, because it gets called fairly
// often.
vl();
}
void *MemRealloc(void *p, int n) { return realloc(p, n); }
void *MemAlloc(int n) { return malloc(n); }
void MemFree(void *p) { free(p); }
static HANDLE Perm;
void *MemRealloc(void *p, int n) {
if(!p) {
return MemAlloc(n);
}
p = HeapReAlloc(Perm, HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY, p, n);
vl();
if(!p) oops();
return p;
}
void *MemAlloc(int n) {
void *p = HeapAlloc(Perm, HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY, n);
vl();
if(!p) oops();
return p;
}
void MemFree(void *p) {
HeapFree(Perm, HEAP_NO_SERIALIZE, p);
vl();
}
void vl(void) {
if(!HeapValidate(Temp, HEAP_NO_SERIALIZE, NULL)) oops();
if(!HeapValidate(Perm, HEAP_NO_SERIALIZE, NULL)) oops();
}
static void PaintTextWnd(HDC hdc)
{
@ -750,6 +775,8 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
ThawWindowPos(TextWnd);
ThawWindowPos(GraphicsWnd);
// Create the heap used for long-lived stuff (that gets freed piecewise).
Perm = HeapCreate(HEAP_NO_SERIALIZE, 1024*1024*20, 0);
// Create the heap that we use to store Exprs and other temp stuff.
FreeAllTemporary();