Add an arc entity. That's not allowed to exist in free space (since
we need something to force the points into plane, and the workplane supplies that), but otherwise straightforward. And add diameter and equal radius constraints for the arc. [git-p4: depot-paths = "//depot/solvespace/": change = 1718]
This commit is contained in:
parent
f4d2651031
commit
364938f332
|
@ -110,6 +110,10 @@ void Constraint::MenuConstrain(int id) {
|
|||
c.type = EQUAL_LENGTH_LINES;
|
||||
c.entityA = gs.entity[0];
|
||||
c.entityB = gs.entity[1];
|
||||
} else if(gs.circlesOrArcs == 2 && gs.n == 2) {
|
||||
c.type = EQUAL_RADIUS;
|
||||
c.entityA = gs.entity[0];
|
||||
c.entityB = gs.entity[1];
|
||||
} else {
|
||||
Error("Bad selection for equal length / radius constraint.");
|
||||
return;
|
||||
|
@ -406,11 +410,19 @@ void Constraint::Generate(IdList<Equation,hEquation> *l) {
|
|||
|
||||
case DIAMETER: {
|
||||
Entity *circle = SS.GetEntity(entityA);
|
||||
Expr *r = (SS.GetEntity(circle->distance))->DistanceGetExpr();
|
||||
Expr *r = circle->CircleGetRadiusExpr();
|
||||
AddEq(l, (r->Times(Expr::FromConstant(2)))->Minus(exprA), 0);
|
||||
break;
|
||||
}
|
||||
|
||||
case EQUAL_RADIUS: {
|
||||
Entity *c1 = SS.GetEntity(entityA);
|
||||
Entity *c2 = SS.GetEntity(entityB);
|
||||
AddEq(l, (c1->CircleGetRadiusExpr())->Minus(
|
||||
c2->CircleGetRadiusExpr()), 0);
|
||||
break;
|
||||
}
|
||||
|
||||
case POINTS_COINCIDENT: {
|
||||
Entity *a = SS.GetEntity(ptA);
|
||||
Entity *b = SS.GetEntity(ptB);
|
||||
|
|
|
@ -171,7 +171,7 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
|
|||
case DIAMETER: {
|
||||
Entity *circle = SS.GetEntity(entityA);
|
||||
Vector center = SS.GetEntity(circle->point[0])->PointGetNum();
|
||||
double r = SS.GetEntity(circle->distance)->DistanceGetNum();
|
||||
double r = circle->CircleGetRadiusNum();
|
||||
Vector ref = center.Plus(disp.offset);
|
||||
|
||||
double theta = atan2(disp.offset.Dot(gu), disp.offset.Dot(gr));
|
||||
|
@ -261,6 +261,32 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
|
|||
break;
|
||||
}
|
||||
|
||||
case EQUAL_RADIUS: {
|
||||
for(int i = 0; i < 2; i++) {
|
||||
Entity *circ = SS.GetEntity(i == 0 ? entityA : entityB);
|
||||
Vector center = SS.GetEntity(circ->point[0])->PointGetNum();
|
||||
double r = circ->CircleGetRadiusNum();
|
||||
Quaternion q = circ->Normal()->NormalGetNum();
|
||||
Vector u = q.RotationU(), v = q.RotationV();
|
||||
|
||||
double theta;
|
||||
if(circ->type == Entity::CIRCLE) {
|
||||
theta = PI/2;
|
||||
} else if(circ->type == Entity::ARC_OF_CIRCLE) {
|
||||
double thetaa, thetab, dtheta;
|
||||
circ->ArcGetAngles(&thetaa, &thetab, &dtheta);
|
||||
theta = thetaa + dtheta/2;
|
||||
} else oops();
|
||||
|
||||
Vector d = u.ScaledBy(cos(theta)).Plus(v.ScaledBy(sin(theta)));
|
||||
d = d.ScaledBy(r);
|
||||
Vector p = center.Plus(d);
|
||||
Vector tick = d.WithMagnitude(10/SS.GW.scale);
|
||||
LineDrawOrGetDistance(p.Plus(tick), p.Minus(tick));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case LENGTH_RATIO:
|
||||
case EQUAL_LENGTH_LINES: {
|
||||
Vector a, b;
|
||||
|
|
1
dsc.h
1
dsc.h
|
@ -53,6 +53,7 @@ public:
|
|||
Vector ProjectInto(hEntity wrkpl);
|
||||
double DivPivoting(Vector delta);
|
||||
Vector ClosestOrtho(void);
|
||||
Point2d Project2d(Vector u, Vector v);
|
||||
};
|
||||
|
||||
class Point2d {
|
||||
|
|
77
entity.cpp
77
entity.cpp
|
@ -76,6 +76,45 @@ bool Entity::IsCircle(void) {
|
|||
return (type == CIRCLE);
|
||||
}
|
||||
|
||||
Expr *Entity::CircleGetRadiusExpr(void) {
|
||||
if(type == CIRCLE) {
|
||||
return SS.GetEntity(distance)->DistanceGetExpr();
|
||||
} else if(type == ARC_OF_CIRCLE) {
|
||||
return Constraint::Distance(workplane, point[0], point[1]);
|
||||
} else oops();
|
||||
}
|
||||
|
||||
double Entity::CircleGetRadiusNum(void) {
|
||||
if(type == CIRCLE) {
|
||||
return SS.GetEntity(distance)->DistanceGetNum();
|
||||
} else if(type == ARC_OF_CIRCLE) {
|
||||
Vector c = SS.GetEntity(point[0])->PointGetNum();
|
||||
Vector pa = SS.GetEntity(point[1])->PointGetNum();
|
||||
return (pa.Minus(c)).Magnitude();
|
||||
} else oops();
|
||||
}
|
||||
|
||||
void Entity::ArcGetAngles(double *thetaa, double *thetab, double *dtheta) {
|
||||
if(type != ARC_OF_CIRCLE) oops();
|
||||
|
||||
Quaternion q = Normal()->NormalGetNum();
|
||||
Vector u = q.RotationU(), v = q.RotationV();
|
||||
|
||||
Vector c = SS.GetEntity(point[0])->PointGetNum();
|
||||
Vector pa = SS.GetEntity(point[1])->PointGetNum();
|
||||
Vector pb = SS.GetEntity(point[2])->PointGetNum();
|
||||
|
||||
Point2d c2 = c.Project2d(u, v);
|
||||
Point2d pa2 = (pa.Project2d(u, v)).Minus(c2);
|
||||
Point2d pb2 = (pb.Project2d(u, v)).Minus(c2);
|
||||
|
||||
*thetaa = atan2(pa2.y, pa2.x);
|
||||
*thetab = atan2(pb2.y, pb2.x);
|
||||
*dtheta = *thetab - *thetaa;
|
||||
while(*dtheta < 0) *dtheta += 2*PI;
|
||||
while(*dtheta > (2*PI)) *dtheta -= 2*PI;
|
||||
}
|
||||
|
||||
bool Entity::IsWorkplane(void) {
|
||||
return (type == WORKPLANE);
|
||||
}
|
||||
|
@ -685,6 +724,33 @@ void Entity::DrawOrGetDistance(int order) {
|
|||
break;
|
||||
}
|
||||
|
||||
case ARC_OF_CIRCLE: {
|
||||
if(order >= 0 && order != 1) break;
|
||||
Vector c = SS.GetEntity(point[0])->PointGetNum();
|
||||
Vector pa = SS.GetEntity(point[1])->PointGetNum();
|
||||
Vector pb = SS.GetEntity(point[2])->PointGetNum();
|
||||
Quaternion q = SS.GetEntity(normal)->NormalGetNum();
|
||||
Vector u = q.RotationU(), v = q.RotationV();
|
||||
|
||||
double ra = (pa.Minus(c)).Magnitude();
|
||||
double rb = (pb.Minus(c)).Magnitude();
|
||||
|
||||
double thetaa, thetab, dtheta;
|
||||
ArcGetAngles(&thetaa, &thetab, &dtheta);
|
||||
|
||||
int i, n = (int)((40*dtheta)/(2*PI));
|
||||
Vector prev = pa;
|
||||
for(i = 1; i <= n; i++) {
|
||||
double theta = thetaa + (dtheta*i)/n;
|
||||
double r = ra + ((rb - ra)*i)/n;
|
||||
Vector d = u.ScaledBy(cos(theta)).Plus(v.ScaledBy(sin(theta)));
|
||||
Vector p = c.Plus(d.ScaledBy(r));
|
||||
LineDrawOrGetDistanceOrEdge(prev, p);
|
||||
prev = p;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case CIRCLE: {
|
||||
if(order >= 0 && order != 1) break;
|
||||
|
||||
|
@ -725,6 +791,17 @@ void Entity::GenerateEquations(IdList<Equation,hEquation> *l) {
|
|||
AddEq(l, (q.Magnitude())->Minus(Expr::FromConstant(1)), 0);
|
||||
break;
|
||||
}
|
||||
case ARC_OF_CIRCLE: {
|
||||
// If this is a copied entity, with its point already fixed
|
||||
// with respect to each other, then we don't want to generate
|
||||
// the distance constraint!
|
||||
if(SS.GetEntity(point[0])->type == POINT_IN_2D) {
|
||||
Expr *ra = Constraint::Distance(workplane, point[0], point[1]);
|
||||
Expr *rb = Constraint::Distance(workplane, point[0], point[2]);
|
||||
AddEq(l, ra->Minus(rb), 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:;
|
||||
// Most entities do not generate equations.
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = {
|
|||
{ 1, "Line &Segment\tS", MNU_LINE_SEGMENT, 'S', mReq },
|
||||
{ 1, "&Rectangle\tR", MNU_RECTANGLE, 'R', mReq },
|
||||
{ 1, "&Circle\tC", MNU_CIRCLE, 'C', mReq },
|
||||
{ 1, "&Arc of a Circle\tA", 0, 'A', mReq },
|
||||
{ 1, "&Arc of a Circle\tA", MNU_ARC, 'A', mReq },
|
||||
{ 1, "&Cubic Segment\t3", MNU_CUBIC, '3', mReq },
|
||||
{ 1, NULL, 0, NULL },
|
||||
{ 1, "Sym&bolic Variable\tB", 0, 'B', mReq },
|
||||
|
@ -350,6 +350,7 @@ void GraphicsWindow::MenuRequest(int id) {
|
|||
case MNU_LINE_SEGMENT: s = "click first point of line segment"; goto c;
|
||||
case MNU_CUBIC: s = "click first point of cubic segment"; goto c;
|
||||
case MNU_CIRCLE: s = "click center of circle"; goto c;
|
||||
case MNU_ARC: s = "click point on arc (draws anti-clockwise)"; goto c;
|
||||
case MNU_WORKPLANE: s = "click origin of workplane"; goto c;
|
||||
case MNU_RECTANGLE: s = "click one corner of rectangular"; goto c;
|
||||
c:
|
||||
|
@ -540,6 +541,7 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown,
|
|||
orig.mouse = mp;
|
||||
} else {
|
||||
UpdateDraggedPoint(pending.point, x, y);
|
||||
HitTestMakeSelection(mp);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -556,6 +558,18 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown,
|
|||
SS.GetEntity(hr.entity(3))->PointForceTo(p2);
|
||||
break;
|
||||
}
|
||||
case DRAGGING_NEW_ARC_POINT: {
|
||||
UpdateDraggedPoint(pending.point, x, y);
|
||||
HitTestMakeSelection(mp);
|
||||
|
||||
hRequest hr = pending.point.request();
|
||||
Vector ona = SS.GetEntity(hr.entity(2))->PointGetNum();
|
||||
Vector onb = SS.GetEntity(hr.entity(3))->PointGetNum();
|
||||
Vector center = (ona.Plus(onb)).ScaledBy(0.5);
|
||||
|
||||
SS.GetEntity(hr.entity(1))->PointForceTo(center);
|
||||
break;
|
||||
}
|
||||
case DRAGGING_NEW_RADIUS:
|
||||
case DRAGGING_RADIUS: {
|
||||
Entity *circle = SS.GetEntity(pending.circle);
|
||||
|
@ -699,6 +713,8 @@ void GraphicsWindow::GroupSelection(void) {
|
|||
switch(e->type) {
|
||||
case Entity::WORKPLANE: (gs.workplanes)++; break;
|
||||
case Entity::LINE_SEGMENT: (gs.lineSegments)++; break;
|
||||
|
||||
case Entity::ARC_OF_CIRCLE:
|
||||
case Entity::CIRCLE: (gs.circlesOrArcs)++; break;
|
||||
}
|
||||
}
|
||||
|
@ -814,6 +830,7 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
|
|||
Entity::NO_ENTITY, Entity::NO_ENTITY,
|
||||
lns[i].entity(0));
|
||||
}
|
||||
ConstrainPointByHovered(lns[2].entity(1));
|
||||
|
||||
pending.operation = DRAGGING_NEW_POINT;
|
||||
pending.point = lns[1].entity(2);
|
||||
|
@ -836,6 +853,26 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
|
|||
SS.GetParam(hr.param(0))->val = 0;
|
||||
break;
|
||||
|
||||
case MNU_ARC:
|
||||
if(SS.GW.activeWorkplane.v == Entity::FREE_IN_3D.v) {
|
||||
Error("Can't draw arc in 3d; select a workplane first.");
|
||||
ClearPending();
|
||||
break;
|
||||
}
|
||||
hr = AddRequest(Request::ARC_OF_CIRCLE);
|
||||
SS.GetEntity(hr.entity(1))->PointForceTo(v);
|
||||
SS.GetEntity(hr.entity(2))->PointForceTo(v);
|
||||
SS.GetEntity(hr.entity(3))->PointForceTo(v);
|
||||
ConstrainPointByHovered(hr.entity(2));
|
||||
|
||||
ClearSelection(); hover.Clear();
|
||||
|
||||
ClearPending();
|
||||
pending.operation = DRAGGING_NEW_ARC_POINT;
|
||||
pending.point = hr.entity(3);
|
||||
pending.description = "click to place point";
|
||||
break;
|
||||
|
||||
case MNU_CUBIC:
|
||||
hr = AddRequest(Request::CUBIC);
|
||||
SS.GetEntity(hr.entity(1))->PointForceTo(v);
|
||||
|
@ -868,6 +905,7 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
|
|||
ClearPending();
|
||||
break;
|
||||
|
||||
case DRAGGING_NEW_ARC_POINT:
|
||||
case DRAGGING_NEW_CUBIC_POINT:
|
||||
ConstrainPointByHovered(pending.point);
|
||||
ClearPending();
|
||||
|
|
13
sketch.cpp
13
sketch.cpp
|
@ -273,6 +273,13 @@ void Group::CopyEntity(hEntity in, int a, hParam dx, hParam dy, hParam dz,
|
|||
en.distance = Remap(ep->distance, a);
|
||||
break;
|
||||
|
||||
case Entity::ARC_OF_CIRCLE:
|
||||
en.point[0] = Remap(ep->point[0], a);
|
||||
en.point[1] = Remap(ep->point[1], a);
|
||||
en.point[2] = Remap(ep->point[2], a);
|
||||
en.normal = Remap(ep->normal, a);
|
||||
break;
|
||||
|
||||
case Entity::POINT_N_COPY:
|
||||
case Entity::POINT_N_TRANS:
|
||||
case Entity::POINT_N_ROT_TRANS:
|
||||
|
@ -511,6 +518,12 @@ void Request::Generate(IdList<Entity,hEntity> *entity,
|
|||
hasDistance = true;
|
||||
break;
|
||||
|
||||
case Request::ARC_OF_CIRCLE:
|
||||
et = Entity::ARC_OF_CIRCLE;
|
||||
points = 3;
|
||||
hasNormal = true;
|
||||
break;
|
||||
|
||||
case Request::CUBIC:
|
||||
et = Entity::CUBIC;
|
||||
points = 4;
|
||||
|
|
6
sketch.h
6
sketch.h
|
@ -153,6 +153,7 @@ public:
|
|||
static const int LINE_SEGMENT = 200;
|
||||
static const int CUBIC = 300;
|
||||
static const int CIRCLE = 400;
|
||||
static const int ARC_OF_CIRCLE = 500;
|
||||
|
||||
int type;
|
||||
|
||||
|
@ -200,6 +201,7 @@ public:
|
|||
static const int LINE_SEGMENT = 11000;
|
||||
static const int CUBIC = 12000;
|
||||
static const int CIRCLE = 13000;
|
||||
static const int ARC_OF_CIRCLE = 14000;
|
||||
|
||||
int type;
|
||||
|
||||
|
@ -227,6 +229,9 @@ public:
|
|||
int timesApplied;
|
||||
|
||||
bool IsCircle(void);
|
||||
Expr *CircleGetRadiusExpr(void);
|
||||
double CircleGetRadiusNum(void);
|
||||
void ArcGetAngles(double *thetaa, double *thetab, double *dtheta);
|
||||
|
||||
bool HasVector(void);
|
||||
ExprVector VectorGetExprs(void);
|
||||
|
@ -333,6 +338,7 @@ public:
|
|||
static const int PT_ON_CIRCLE = 100;
|
||||
static const int SAME_ORIENTATION = 110;
|
||||
static const int PARALLEL = 120;
|
||||
static const int EQUAL_RADIUS = 130;
|
||||
|
||||
int tag;
|
||||
hConstraint h;
|
||||
|
|
|
@ -344,7 +344,7 @@ bool System::NewtonSolve(int tag) {
|
|||
}
|
||||
|
||||
bool System::Solve(void) {
|
||||
int i, j;
|
||||
int i, j = 0;
|
||||
|
||||
/*
|
||||
dbp("%d equations", eq.n);
|
||||
|
|
10
ui.h
10
ui.h
|
@ -105,6 +105,7 @@ public:
|
|||
MNU_WORKPLANE,
|
||||
MNU_LINE_SEGMENT,
|
||||
MNU_CIRCLE,
|
||||
MNU_ARC,
|
||||
MNU_RECTANGLE,
|
||||
MNU_CUBIC,
|
||||
MNU_CONSTRUCTION,
|
||||
|
@ -184,10 +185,11 @@ public:
|
|||
static const int DRAGGING_NEW_POINT = 0x0f000001;
|
||||
static const int DRAGGING_NEW_LINE_POINT = 0x0f000002;
|
||||
static const int DRAGGING_NEW_CUBIC_POINT = 0x0f000003;
|
||||
static const int DRAGGING_CONSTRAINT = 0x0f000004;
|
||||
static const int DRAGGING_RADIUS = 0x0f000005;
|
||||
static const int DRAGGING_NORMAL = 0x0f000006;
|
||||
static const int DRAGGING_NEW_RADIUS = 0x0f000007;
|
||||
static const int DRAGGING_NEW_ARC_POINT = 0x0f000004;
|
||||
static const int DRAGGING_CONSTRAINT = 0x0f000005;
|
||||
static const int DRAGGING_RADIUS = 0x0f000006;
|
||||
static const int DRAGGING_NORMAL = 0x0f000007;
|
||||
static const int DRAGGING_NEW_RADIUS = 0x0f000008;
|
||||
struct {
|
||||
int operation;
|
||||
|
||||
|
|
7
util.cpp
7
util.cpp
|
@ -298,6 +298,13 @@ Vector Vector::ProjectInto(hEntity wrkpl) {
|
|||
return p0.Plus((u.ScaledBy(up)).Plus(v.ScaledBy(vp)));
|
||||
}
|
||||
|
||||
Point2d Vector::Project2d(Vector u, Vector v) {
|
||||
Point2d p;
|
||||
p.x = this->Dot(u);
|
||||
p.y = this->Dot(v);
|
||||
return p;
|
||||
}
|
||||
|
||||
double Vector::DivPivoting(Vector delta) {
|
||||
double m = max(fabs(delta.x), max(fabs(delta.y), fabs(delta.z)));
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user