From e99eedd7a3f35a472215f60c9ef208f32ddc5084 Mon Sep 17 00:00:00 2001 From: EvilSpirit Date: Sun, 28 Feb 2016 23:08:23 +0600 Subject: [PATCH] Check entity bounding box before hit testing edges. --- src/draw.cpp | 4 ++-- src/drawentity.cpp | 40 ++++++++++++++++++++++++++++++++++++++++ src/dsc.h | 1 + src/sketch.h | 1 + src/ui.h | 2 ++ src/util.cpp | 4 ++++ 6 files changed, 50 insertions(+), 2 deletions(-) diff --git a/src/draw.cpp b/src/draw.cpp index cbd40630..31ab9985 100644 --- a/src/draw.cpp +++ b/src/draw.cpp @@ -336,7 +336,7 @@ void GraphicsWindow::HitTestMakeSelection(Point2d mp) { } d = e->GetDistance(mp); - if(d < 10 && d < dmin) { + if(d < SELECTION_RADIUS && d < dmin) { s = {}; s.entity = e->h; dmin = d; @@ -348,7 +348,7 @@ void GraphicsWindow::HitTestMakeSelection(Point2d mp) { // Constraints for(i = 0; i < SK.constraint.n; i++) { d = SK.constraint.elem[i].GetDistance(mp); - if(d < 10 && d < dmin) { + if(d < SELECTION_RADIUS && d < dmin) { s = {}; s.constraint = SK.constraint.elem[i].h; dmin = d; diff --git a/src/drawentity.cpp b/src/drawentity.cpp index 3f2ae82f..10a7c1d9 100644 --- a/src/drawentity.cpp +++ b/src/drawentity.cpp @@ -152,6 +152,37 @@ SEdgeList *Entity::GetOrGenerateEdges() { 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) { dogd.drawing = false; dogd.mp = mp; @@ -473,6 +504,15 @@ void Entity::GenerateBezierCurves(SBezierList *sbl) { } 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; switch(type) { diff --git a/src/dsc.h b/src/dsc.h index 47281491..ade8ce7f 100644 --- a/src/dsc.h +++ b/src/dsc.h @@ -513,6 +513,7 @@ public: void Include(const Vector &v, double r = 0.0); bool Overlaps(BBox &b1); + bool Contains(const Point2d &p); }; #endif diff --git a/src/sketch.h b/src/sketch.h index 8e789b62..fe920743 100644 --- a/src/sketch.h +++ b/src/sketch.h @@ -509,6 +509,7 @@ public: SBezierList *GetOrGenerateBezierCurves(); SEdgeList *GetOrGenerateEdges(); + BBox GetScreenBBox(bool *hasBBox); void Clear() { beziers.l.Clear(); diff --git a/src/ui.h b/src/ui.h index 719b5953..6cacaf25 100644 --- a/src/ui.h +++ b/src/ui.h @@ -328,6 +328,8 @@ public: void EditControlDone(const char *s); }; +#define SELECTION_RADIUS 10.0 + class GraphicsWindow { public: void Init(void); diff --git a/src/util.cpp b/src/util.cpp index 6280e089..f1c50e4b 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -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; } + +bool BBox::Contains(const Point2d &p) { + return p.x >= minp.x && p.y >= minp.y && p.x <= maxp.x && p.y <= maxp.y; +}