Also consider constraints when zooming to fit.

Before this commit, when working on convex sketches, zooming to fit
was guaranteed to clip most or even all constraints, making it quite
useless.
This commit is contained in:
whitequark 2016-08-01 14:00:00 +00:00
parent 8e7d2eaa84
commit f2633e4a57
3 changed files with 42 additions and 20 deletions

View File

@ -13,6 +13,7 @@ Other new features:
"Analyze → Measure Perimeter". "Analyze → Measure Perimeter".
* New link to match the on-screen size of the sketch with its actual size, * New link to match the on-screen size of the sketch with its actual size,
"view → set to full scale". "view → set to full scale".
* When zooming to fit, constraints are also considered.
2.2 2.2
--- ---

View File

@ -313,11 +313,11 @@ void GraphicsWindow::HandlePointForZoomToFit(Vector p, Point2d *pmax, Point2d *p
*wmin = min(*wmin, w); *wmin = min(*wmin, w);
} }
void GraphicsWindow::LoopOverPoints(const std::vector<Entity *> &entities, void GraphicsWindow::LoopOverPoints(const std::vector<Entity *> &entities,
const std::vector<Constraint *> &constraints,
const std::vector<hEntity> &faces, const std::vector<hEntity> &faces,
Point2d *pmax, Point2d *pmin, double *wmin, Point2d *pmax, Point2d *pmin, double *wmin,
bool usePerspective, bool includeMesh) { bool usePerspective, bool includeMesh) {
int i, j;
for(Entity *e : entities) { for(Entity *e : entities) {
if(e->IsPoint()) { if(e->IsPoint()) {
HandlePointForZoomToFit(e->PointGetNum(), pmax, pmin, wmin, usePerspective); HandlePointForZoomToFit(e->PointGetNum(), pmax, pmin, wmin, usePerspective);
@ -329,7 +329,7 @@ void GraphicsWindow::LoopOverPoints(const std::vector<Entity *> &entities,
double r = e->CircleGetRadiusNum(); double r = e->CircleGetRadiusNum();
Vector c = SK.GetEntity(e->point[0])->PointGetNum(); Vector c = SK.GetEntity(e->point[0])->PointGetNum();
Quaternion q = SK.GetEntity(e->normal)->NormalGetNum(); Quaternion q = SK.GetEntity(e->normal)->NormalGetNum();
for(j = 0; j < 4; j++) { for(int j = 0; j < 4; j++) {
Vector p = (j == 0) ? (c.Plus(q.RotationU().ScaledBy( r))) : Vector p = (j == 0) ? (c.Plus(q.RotationU().ScaledBy( r))) :
(j == 1) ? (c.Plus(q.RotationU().ScaledBy(-r))) : (j == 1) ? (c.Plus(q.RotationU().ScaledBy(-r))) :
(j == 2) ? (c.Plus(q.RotationV().ScaledBy( r))) : (j == 2) ? (c.Plus(q.RotationV().ScaledBy( r))) :
@ -346,11 +346,19 @@ void GraphicsWindow::LoopOverPoints(const std::vector<Entity *> &entities,
} }
} }
for(Constraint *c : constraints) {
std::vector<Vector> refs;
c->GetReferencePoints(GetCamera(), &refs);
for(Vector p : refs) {
HandlePointForZoomToFit(p, pmax, pmin, wmin, usePerspective);
}
}
if(!includeMesh && faces.empty()) return; if(!includeMesh && faces.empty()) return;
Group *g = SK.GetGroup(activeGroup); Group *g = SK.GetGroup(activeGroup);
g->GenerateDisplayItems(); g->GenerateDisplayItems();
for(i = 0; i < g->displayMesh.l.n; i++) { for(int i = 0; i < g->displayMesh.l.n; i++) {
STriangle *tr = &(g->displayMesh.l.elem[i]); STriangle *tr = &(g->displayMesh.l.elem[i]);
if(!includeMesh) { if(!includeMesh) {
bool found = false; bool found = false;
@ -366,46 +374,56 @@ void GraphicsWindow::LoopOverPoints(const std::vector<Entity *> &entities,
HandlePointForZoomToFit(tr->c, pmax, pmin, wmin, usePerspective); HandlePointForZoomToFit(tr->c, pmax, pmin, wmin, usePerspective);
} }
if(!includeMesh) return; if(!includeMesh) return;
for(i = 0; i < g->polyLoops.l.n; i++) { for(int i = 0; i < g->polyLoops.l.n; i++) {
SContour *sc = &(g->polyLoops.l.elem[i]); SContour *sc = &(g->polyLoops.l.elem[i]);
for(j = 0; j < sc->l.n; j++) { for(int j = 0; j < sc->l.n; j++) {
HandlePointForZoomToFit(sc->l.elem[j].p, pmax, pmin, wmin, usePerspective); HandlePointForZoomToFit(sc->l.elem[j].p, pmax, pmin, wmin, usePerspective);
} }
} }
} }
void GraphicsWindow::ZoomToFit(bool includingInvisibles, bool useSelection) { void GraphicsWindow::ZoomToFit(bool includingInvisibles, bool useSelection) {
std::vector<Entity *> entities; std::vector<Entity *> entities;
std::vector<Constraint *> constraints;
std::vector<hEntity> faces; std::vector<hEntity> faces;
if(useSelection) { if(useSelection) {
for(int i = 0; i < selection.n; i++) { for(int i = 0; i < selection.n; i++) {
Selection *s = &selection.elem[i]; Selection *s = &selection.elem[i];
if(s->entity.v == 0) continue; if(s->entity.v != 0) {
Entity *e = SK.entity.FindById(s->entity); Entity *e = SK.entity.FindById(s->entity);
if(e->IsFace()) { if(e->IsFace()) {
faces.push_back(e->h); faces.push_back(e->h);
continue; continue;
}
entities.push_back(e);
}
if(s->constraint.v != 0) {
Constraint *c = SK.constraint.FindById(s->constraint);
constraints.push_back(c);
} }
entities.push_back(e);
} }
} }
bool selectionUsed = !entities.empty() || !faces.empty(); bool selectionUsed = !entities.empty() || !constraints.empty() || !faces.empty();
if(!selectionUsed) { if(!selectionUsed) {
for(int i = 0; i<SK.entity.n; i++) { for(Entity &e : SK.entity) {
Entity *e = &(SK.entity.elem[i]);
// we don't want to handle separate points, because we will iterate them inside entities. // we don't want to handle separate points, because we will iterate them inside entities.
if(e->IsPoint()) continue; if(e.IsPoint()) continue;
if(!includingInvisibles && !e->IsVisible()) continue; if(!includingInvisibles && !e.IsVisible()) continue;
entities.push_back(e); entities.push_back(&e);
}
for(Constraint &c : SK.constraint) {
if(!c.IsVisible()) continue;
constraints.push_back(&c);
} }
} }
// On the first run, ignore perspective. // On the first run, ignore perspective.
Point2d pmax = { -1e12, -1e12 }, pmin = { 1e12, 1e12 }; Point2d pmax = { -1e12, -1e12 }, pmin = { 1e12, 1e12 };
double wmin = 1; double wmin = 1;
LoopOverPoints(entities, faces, &pmax, &pmin, &wmin, LoopOverPoints(entities, constraints, faces, &pmax, &pmin, &wmin,
/*usePerspective=*/false, /*includeMesh=*/!selectionUsed); /*usePerspective=*/false, /*includeMesh=*/!selectionUsed);
double xm = (pmax.x + pmin.x)/2, ym = (pmax.y + pmin.y)/2; double xm = (pmax.x + pmin.x)/2, ym = (pmax.y + pmin.y)/2;
@ -431,7 +449,7 @@ void GraphicsWindow::ZoomToFit(bool includingInvisibles, bool useSelection) {
pmax.x = -1e12; pmax.y = -1e12; pmax.x = -1e12; pmax.y = -1e12;
pmin.x = 1e12; pmin.y = 1e12; pmin.x = 1e12; pmin.y = 1e12;
wmin = 1; wmin = 1;
LoopOverPoints(entities, faces, &pmax, &pmin, &wmin, LoopOverPoints(entities, constraints, faces, &pmax, &pmin, &wmin,
/*usePerspective=*/true, /*includeMesh=*/!selectionUsed); /*usePerspective=*/true, /*includeMesh=*/!selectionUsed);
// Adjust the scale so that no points are behind the camera // Adjust the scale so that no points are behind the camera

View File

@ -559,7 +559,10 @@ public:
Vector VectorFromProjs(Vector rightUpForward); Vector VectorFromProjs(Vector rightUpForward);
void HandlePointForZoomToFit(Vector p, Point2d *pmax, Point2d *pmin, void HandlePointForZoomToFit(Vector p, Point2d *pmax, Point2d *pmin,
double *wmin, bool usePerspective); double *wmin, bool usePerspective);
void LoopOverPoints(const std::vector<Entity *> &entity, const std::vector<hEntity> &faces, Point2d *pmax, Point2d *pmin, void LoopOverPoints(const std::vector<Entity *> &entities,
const std::vector<Constraint *> &constraints,
const std::vector<hEntity> &faces,
Point2d *pmax, Point2d *pmin,
double *wmin, bool usePerspective, bool includeMesh); double *wmin, bool usePerspective, bool includeMesh);
void ZoomToFit(bool includingInvisibles, bool useSelection = false); void ZoomToFit(bool includingInvisibles, bool useSelection = false);