Use entity bounding boxes in SelectByMarquee.
Also, fix an insidious typo in BBox::GetOrigin that made BBox::Overlap return nonsensical results.pull/10/head
parent
e2916e3e4a
commit
68c4d6f704
47
src/draw.cpp
47
src/draw.cpp
|
@ -187,16 +187,12 @@ void GraphicsWindow::MakeSelected(Selection *stog) {
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Select everything that lies within the marquee view-aligned rectangle. For
|
// Select everything that lies within the marquee view-aligned rectangle.
|
||||||
// points, we test by the point location. For normals, we test by the normal's
|
|
||||||
// associated point. For anything else, we test by any piecewise linear edge.
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
void GraphicsWindow::SelectByMarquee() {
|
void GraphicsWindow::SelectByMarquee() {
|
||||||
Point2d begin = ProjectPoint(orig.marqueePoint);
|
Point2d marqueePoint = ProjectPoint(orig.marqueePoint);
|
||||||
double xmin = min(orig.mouse.x, begin.x),
|
BBox marqueeBBox = BBox::From(Vector::From(marqueePoint.x, marqueePoint.y, -1),
|
||||||
xmax = max(orig.mouse.x, begin.x),
|
Vector::From(orig.mouse.x, orig.mouse.y, 1));
|
||||||
ymin = min(orig.mouse.y, begin.y),
|
|
||||||
ymax = max(orig.mouse.y, begin.y);
|
|
||||||
|
|
||||||
Entity *e;
|
Entity *e;
|
||||||
for(e = SK.entity.First(); e; e = SK.entity.NextAfter(e)) {
|
for(e = SK.entity.First(); e; e = SK.entity.NextAfter(e)) {
|
||||||
|
@ -204,40 +200,11 @@ void GraphicsWindow::SelectByMarquee() {
|
||||||
if(e->IsFace() || e->IsDistance()) continue;
|
if(e->IsFace() || e->IsDistance()) continue;
|
||||||
if(!e->IsVisible()) continue;
|
if(!e->IsVisible()) continue;
|
||||||
|
|
||||||
if(e->IsPoint() || e->IsNormal()) {
|
bool entityHasBBox;
|
||||||
Vector p = e->IsPoint() ? e->PointGetNum() :
|
BBox entityBBox = e->GetOrGenerateScreenBBox(&entityHasBBox);
|
||||||
SK.GetEntity(e->point[0])->PointGetNum();
|
if(entityHasBBox && entityBBox.Overlaps(marqueeBBox)) {
|
||||||
Point2d pp = ProjectPoint(p);
|
|
||||||
if(pp.x >= xmin && pp.x <= xmax &&
|
|
||||||
pp.y >= ymin && pp.y <= ymax)
|
|
||||||
{
|
|
||||||
MakeSelected(e->h);
|
MakeSelected(e->h);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// Use the 3d bounding box test routines, to avoid duplication;
|
|
||||||
// so let our bounding square become a bounding box that certainly
|
|
||||||
// includes the z = 0 plane.
|
|
||||||
Vector ptMin = Vector::From(xmin, ymin, -1),
|
|
||||||
ptMax = Vector::From(xmax, ymax, 1);
|
|
||||||
SEdgeList sel = {};
|
|
||||||
e->GenerateEdges(&sel, true);
|
|
||||||
SEdge *se;
|
|
||||||
for(se = sel.l.First(); se; se = sel.l.NextAfter(se)) {
|
|
||||||
Point2d ppa = ProjectPoint(se->a),
|
|
||||||
ppb = ProjectPoint(se->b);
|
|
||||||
Vector ptA = Vector::From(ppa.x, ppa.y, 0),
|
|
||||||
ptB = Vector::From(ppb.x, ppb.y, 0);
|
|
||||||
if(Vector::BoundingBoxIntersectsLine(ptMax, ptMin,
|
|
||||||
ptA, ptB, true) ||
|
|
||||||
!ptA.OutsideAndNotOn(ptMax, ptMin) ||
|
|
||||||
!ptB.OutsideAndNotOn(ptMax, ptMin))
|
|
||||||
{
|
|
||||||
MakeSelected(e->h);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sel.Clear();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -160,8 +160,8 @@ SEdgeList *Entity::GetOrGenerateEdges() {
|
||||||
BBox Entity::GetOrGenerateScreenBBox(bool *hasBBox) {
|
BBox Entity::GetOrGenerateScreenBBox(bool *hasBBox) {
|
||||||
SBezierList *sbl = GetOrGenerateBezierCurves();
|
SBezierList *sbl = GetOrGenerateBezierCurves();
|
||||||
|
|
||||||
// We don't bother with bounding boxes for normals, workplanes, etc.
|
// We don't bother with bounding boxes for workplanes, etc.
|
||||||
*hasBBox = (IsPoint() || sbl->l.n > 0);
|
*hasBBox = (IsPoint() || IsNormal() || sbl->l.n > 0);
|
||||||
if(!*hasBBox) return {};
|
if(!*hasBBox) return {};
|
||||||
|
|
||||||
if(screenBBoxValid)
|
if(screenBBoxValid)
|
||||||
|
@ -170,6 +170,9 @@ BBox Entity::GetOrGenerateScreenBBox(bool *hasBBox) {
|
||||||
if(IsPoint()) {
|
if(IsPoint()) {
|
||||||
Vector proj = SS.GW.ProjectPoint3(PointGetNum());
|
Vector proj = SS.GW.ProjectPoint3(PointGetNum());
|
||||||
screenBBox = BBox::From(proj, proj);
|
screenBBox = BBox::From(proj, proj);
|
||||||
|
} else if(IsNormal()) {
|
||||||
|
Vector proj = SK.GetEntity(point[0])->PointGetNum();
|
||||||
|
screenBBox = BBox::From(proj, proj);
|
||||||
} else if(sbl->l.n > 0) {
|
} else if(sbl->l.n > 0) {
|
||||||
Vector first = SS.GW.ProjectPoint3(sbl->l.elem[0].ctrl[0]);
|
Vector first = SS.GW.ProjectPoint3(sbl->l.elem[0].ctrl[0]);
|
||||||
screenBBox = BBox::From(first, first);
|
screenBBox = BBox::From(first, first);
|
||||||
|
@ -181,12 +184,6 @@ BBox Entity::GetOrGenerateScreenBBox(bool *hasBBox) {
|
||||||
}
|
}
|
||||||
} else ssassert(false, "Expected entity to be a point or have beziers");
|
} else ssassert(false, "Expected entity to be a point or have beziers");
|
||||||
|
|
||||||
// Enlarge the bounding box to consider selection radius.
|
|
||||||
screenBBox.minp.x -= SELECTION_RADIUS;
|
|
||||||
screenBBox.minp.y -= SELECTION_RADIUS;
|
|
||||||
screenBBox.maxp.x += SELECTION_RADIUS;
|
|
||||||
screenBBox.maxp.y += SELECTION_RADIUS;
|
|
||||||
|
|
||||||
screenBBoxValid = true;
|
screenBBoxValid = true;
|
||||||
return screenBBox;
|
return screenBBox;
|
||||||
}
|
}
|
||||||
|
@ -521,10 +518,10 @@ void Entity::GenerateBezierCurves(SBezierList *sbl) const {
|
||||||
void Entity::DrawOrGetDistance() {
|
void Entity::DrawOrGetDistance() {
|
||||||
// If we're about to perform hit testing on an entity, consider
|
// If we're about to perform hit testing on an entity, consider
|
||||||
// whether the pointer is inside its bounding box first.
|
// whether the pointer is inside its bounding box first.
|
||||||
if(!dogd.drawing) {
|
if(!dogd.drawing && !IsNormal()) {
|
||||||
bool hasBBox;
|
bool hasBBox;
|
||||||
BBox box = GetOrGenerateScreenBBox(&hasBBox);
|
BBox box = GetOrGenerateScreenBBox(&hasBBox);
|
||||||
if(hasBBox && !box.Contains(dogd.mp))
|
if(hasBBox && !box.Contains(dogd.mp, SELECTION_RADIUS))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -528,7 +528,7 @@ public:
|
||||||
|
|
||||||
void Include(const Vector &v, double r = 0.0);
|
void Include(const Vector &v, double r = 0.0);
|
||||||
bool Overlaps(const BBox &b1) const;
|
bool Overlaps(const BBox &b1) const;
|
||||||
bool Contains(const Point2d &p) const;
|
bool Contains(const Point2d &p, double r = 0.0) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
10
src/util.cpp
10
src/util.cpp
|
@ -1036,7 +1036,7 @@ BBox BBox::From(const Vector &p0, const Vector &p1) {
|
||||||
return bbox;
|
return bbox;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector BBox::GetOrigin() const { return minp.Plus(maxp.Minus(minp)).ScaledBy(0.5); }
|
Vector BBox::GetOrigin() const { return minp.Plus(maxp.Minus(minp).ScaledBy(0.5)); }
|
||||||
Vector BBox::GetExtents() const { return maxp.Minus(minp).ScaledBy(0.5); }
|
Vector BBox::GetExtents() const { return maxp.Minus(minp).ScaledBy(0.5); }
|
||||||
|
|
||||||
void BBox::Include(const Vector &v, double r) {
|
void BBox::Include(const Vector &v, double r) {
|
||||||
|
@ -1050,13 +1050,15 @@ void BBox::Include(const Vector &v, double r) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BBox::Overlaps(const BBox &b1) const {
|
bool BBox::Overlaps(const BBox &b1) const {
|
||||||
|
|
||||||
Vector t = b1.GetOrigin().Minus(GetOrigin());
|
Vector t = b1.GetOrigin().Minus(GetOrigin());
|
||||||
Vector e = b1.GetExtents().Plus(GetExtents());
|
Vector e = b1.GetExtents().Plus(GetExtents());
|
||||||
|
|
||||||
return fabs(t.x) < e.x && fabs(t.y) < e.y && fabs(t.z) < e.z;
|
return fabs(t.x) < e.x && fabs(t.y) < e.y && fabs(t.z) < e.z;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BBox::Contains(const Point2d &p) const {
|
bool BBox::Contains(const Point2d &p, double r) const {
|
||||||
return p.x >= minp.x && p.y >= minp.y && p.x <= maxp.x && p.y <= maxp.y;
|
return p.x >= (minp.x - r) &&
|
||||||
|
p.y >= (minp.y - r) &&
|
||||||
|
p.x <= (maxp.x + r) &&
|
||||||
|
p.y <= (maxp.y + r);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue