Check entity bounding box before hit testing edges.

pull/4/head
EvilSpirit 2016-02-28 23:08:23 +06:00 committed by whitequark
parent b054b9682a
commit e99eedd7a3
6 changed files with 50 additions and 2 deletions

View File

@ -336,7 +336,7 @@ void GraphicsWindow::HitTestMakeSelection(Point2d mp) {
} }
d = e->GetDistance(mp); d = e->GetDistance(mp);
if(d < 10 && d < dmin) { if(d < SELECTION_RADIUS && d < dmin) {
s = {}; s = {};
s.entity = e->h; s.entity = e->h;
dmin = d; dmin = d;
@ -348,7 +348,7 @@ void GraphicsWindow::HitTestMakeSelection(Point2d mp) {
// Constraints // Constraints
for(i = 0; i < SK.constraint.n; i++) { for(i = 0; i < SK.constraint.n; i++) {
d = SK.constraint.elem[i].GetDistance(mp); d = SK.constraint.elem[i].GetDistance(mp);
if(d < 10 && d < dmin) { if(d < SELECTION_RADIUS && d < dmin) {
s = {}; s = {};
s.constraint = SK.constraint.elem[i].h; s.constraint = SK.constraint.elem[i].h;
dmin = d; dmin = d;

View File

@ -152,6 +152,37 @@ SEdgeList *Entity::GetOrGenerateEdges() {
return &edges; return &edges;
} }
BBox Entity::GetScreenBBox(bool *hasBBox) {
SBezierList *sbl = GetOrGenerateBezierCurves();
// We don't bother with bounding boxes for normals, workplanes, etc.
*hasBBox = (IsPoint() || sbl->l.n > 0);
if(!*hasBBox) return {};
BBox result = {};
if(IsPoint()) {
Vector proj = SS.GW.ProjectPoint3(PointGetNum());
result = BBox::From(proj, proj);
} else if(sbl->l.n > 0) {
Vector first = SS.GW.ProjectPoint3(sbl->l.elem[0].ctrl[0]);
result = BBox::From(first, first);
for(int i = 0; i < sbl->l.n; i++) {
SBezier *sb = &sbl->l.elem[i];
for(int i = 0; i <= sb->deg; i++) {
result.Include(SS.GW.ProjectPoint3(sb->ctrl[i]));
}
}
} else oops();
// Enlarge the bounding box to consider selection radius.
result.minp.x -= SELECTION_RADIUS;
result.minp.y -= SELECTION_RADIUS;
result.maxp.x += SELECTION_RADIUS;
result.maxp.y += SELECTION_RADIUS;
return result;
}
double Entity::GetDistance(Point2d mp) { double Entity::GetDistance(Point2d mp) {
dogd.drawing = false; dogd.drawing = false;
dogd.mp = mp; dogd.mp = mp;
@ -473,6 +504,15 @@ void Entity::GenerateBezierCurves(SBezierList *sbl) {
} }
void Entity::DrawOrGetDistance(void) { void Entity::DrawOrGetDistance(void) {
// If we're about to perform hit testing on an entity, consider
// whether the pointer is inside its bounding box first.
if(!dogd.drawing) {
bool hasBBox;
BBox box = GetScreenBBox(&hasBBox);
if(hasBBox && !box.Contains(dogd.mp))
return;
}
if(!IsVisible()) return; if(!IsVisible()) return;
switch(type) { switch(type) {

View File

@ -513,6 +513,7 @@ public:
void Include(const Vector &v, double r = 0.0); void Include(const Vector &v, double r = 0.0);
bool Overlaps(BBox &b1); bool Overlaps(BBox &b1);
bool Contains(const Point2d &p);
}; };
#endif #endif

View File

@ -509,6 +509,7 @@ public:
SBezierList *GetOrGenerateBezierCurves(); SBezierList *GetOrGenerateBezierCurves();
SEdgeList *GetOrGenerateEdges(); SEdgeList *GetOrGenerateEdges();
BBox GetScreenBBox(bool *hasBBox);
void Clear() { void Clear() {
beziers.l.Clear(); beziers.l.Clear();

View File

@ -328,6 +328,8 @@ public:
void EditControlDone(const char *s); void EditControlDone(const char *s);
}; };
#define SELECTION_RADIUS 10.0
class GraphicsWindow { class GraphicsWindow {
public: public:
void Init(void); void Init(void);

View File

@ -1047,3 +1047,7 @@ bool BBox::Overlaps(BBox &b1) {
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) {
return p.x >= minp.x && p.y >= minp.y && p.x <= maxp.x && p.y <= maxp.y;
}