Add z distance checking to entity picking. Fixes issue 521

pull/799/head
phkahler 2020-11-16 20:40:27 -05:00
parent 6c2b967790
commit 142252ddf8
4 changed files with 24 additions and 7 deletions

View File

@ -342,6 +342,8 @@ GraphicsWindow::Selection GraphicsWindow::ChooseFromHoverToSelect() {
Group *activeGroup = SK.GetGroup(SS.GW.activeGroup); Group *activeGroup = SK.GetGroup(SS.GW.activeGroup);
int bestOrder = -1; int bestOrder = -1;
int bestZIndex = 0; int bestZIndex = 0;
double bestDepth = VERY_POSITIVE;
for(const Hover &hov : hoverList) { for(const Hover &hov : hoverList) {
hGroup hg = {}; hGroup hg = {};
if(hov.selection.entity.v != 0) { if(hov.selection.entity.v != 0) {
@ -353,8 +355,11 @@ GraphicsWindow::Selection GraphicsWindow::ChooseFromHoverToSelect() {
Group *g = SK.GetGroup(hg); Group *g = SK.GetGroup(hg);
if(g->order > activeGroup->order) continue; if(g->order > activeGroup->order) continue;
if(bestOrder != -1 && (bestOrder > g->order || bestZIndex > hov.zIndex)) continue; if(bestOrder != -1 && (bestOrder > g->order || bestZIndex > hov.zIndex)) continue;
// we have hov.zIndex is >= best and hov.group is >= best (but not > active group)
if(hov.depth > bestDepth && bestOrder == g->order && bestZIndex == hov.zIndex) continue;
bestOrder = g->order; bestOrder = g->order;
bestZIndex = hov.zIndex; bestZIndex = hov.zIndex;
bestDepth = hov.depth;
sel = hov.selection; sel = hov.selection;
} }
return sel; return sel;
@ -370,6 +375,8 @@ GraphicsWindow::Selection GraphicsWindow::ChooseFromHoverToDrag() {
Group *activeGroup = SK.GetGroup(SS.GW.activeGroup); Group *activeGroup = SK.GetGroup(SS.GW.activeGroup);
int bestOrder = -1; int bestOrder = -1;
int bestZIndex = 0; int bestZIndex = 0;
double bestDepth = VERY_POSITIVE;
for(const Hover &hov : hoverList) { for(const Hover &hov : hoverList) {
hGroup hg = {}; hGroup hg = {};
if(hov.selection.entity.v != 0) { if(hov.selection.entity.v != 0) {
@ -383,6 +390,8 @@ GraphicsWindow::Selection GraphicsWindow::ChooseFromHoverToDrag() {
Group *g = SK.GetGroup(hg); Group *g = SK.GetGroup(hg);
if(g->order > activeGroup->order) continue; if(g->order > activeGroup->order) continue;
if(bestOrder != -1 && (bestOrder > g->order || bestZIndex > hov.zIndex)) continue; if(bestOrder != -1 && (bestOrder > g->order || bestZIndex > hov.zIndex)) continue;
// we have hov.zIndex is >= best and hov.group is >= best (but not > active group)
if(hov.depth > bestDepth && bestOrder == g->order && bestZIndex == hov.zIndex) continue;
bestOrder = g->order; bestOrder = g->order;
bestZIndex = hov.zIndex; bestZIndex = hov.zIndex;
sel = hov.selection; sel = hov.selection;
@ -439,6 +448,7 @@ void GraphicsWindow::HitTestMakeSelection(Point2d mp) {
Hover hov = {}; Hover hov = {};
hov.distance = canvas.minDistance; hov.distance = canvas.minDistance;
hov.zIndex = canvas.maxZIndex; hov.zIndex = canvas.maxZIndex;
hov.depth = canvas.minDepth;
hov.selection.entity = e.h; hov.selection.entity = e.h;
hoverList.Add(&hov); hoverList.Add(&hov);
} }

View File

@ -343,9 +343,10 @@ void UiCanvas::DrawBitmapText(const std::string &str, int x, int y, RgbaColor co
// A canvas that performs picking against drawn geometry. // A canvas that performs picking against drawn geometry.
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void ObjectPicker::DoCompare(double distance, int zIndex, int comparePosition) { void ObjectPicker::DoCompare(double depth, double distance, int zIndex, int comparePosition) {
if(distance > selRadius) return; if(distance > selRadius) return;
if((zIndex == maxZIndex && distance < minDistance) || (zIndex > maxZIndex)) { if((zIndex == maxZIndex && distance < minDistance) || (zIndex > maxZIndex)) {
minDepth = depth;
minDistance = distance; minDistance = distance;
maxZIndex = zIndex; maxZIndex = zIndex;
position = comparePosition; position = comparePosition;
@ -372,10 +373,10 @@ void ObjectPicker::DoQuad(const Vector &a, const Vector &b, const Vector &c, con
bool insideQuad = (minNegative == VERY_NEGATIVE || maxPositive == VERY_POSITIVE); bool insideQuad = (minNegative == VERY_NEGATIVE || maxPositive == VERY_POSITIVE);
if(insideQuad) { if(insideQuad) {
DoCompare(0.0, zIndex, comparePosition); DoCompare(0, 0.0, zIndex, comparePosition);
} else { } else {
double distance = std::min(fabs(minNegative), fabs(maxPositive)); double distance = std::min(fabs(minNegative), fabs(maxPositive));
DoCompare(distance, zIndex, comparePosition); DoCompare(0, distance, zIndex, comparePosition);
} }
} }
@ -384,7 +385,8 @@ void ObjectPicker::DrawLine(const Vector &a, const Vector &b, hStroke hcs) {
Point2d ap = camera.ProjectPoint(a); Point2d ap = camera.ProjectPoint(a);
Point2d bp = camera.ProjectPoint(b); Point2d bp = camera.ProjectPoint(b);
double distance = point.DistanceToLine(ap, bp.Minus(ap), /*asSegment=*/true); double distance = point.DistanceToLine(ap, bp.Minus(ap), /*asSegment=*/true);
DoCompare(distance - stroke->width / 2.0, stroke->zIndex); double depth = 0.5 * (camera.ProjectPoint3(a).z + camera.ProjectPoint3(b).z) ;
DoCompare(depth, distance - stroke->width / 2.0, stroke->zIndex);
} }
void ObjectPicker::DrawEdges(const SEdgeList &el, hStroke hcs) { void ObjectPicker::DrawEdges(const SEdgeList &el, hStroke hcs) {
@ -393,7 +395,8 @@ void ObjectPicker::DrawEdges(const SEdgeList &el, hStroke hcs) {
Point2d ap = camera.ProjectPoint(e.a); Point2d ap = camera.ProjectPoint(e.a);
Point2d bp = camera.ProjectPoint(e.b); Point2d bp = camera.ProjectPoint(e.b);
double distance = point.DistanceToLine(ap, bp.Minus(ap), /*asSegment=*/true); double distance = point.DistanceToLine(ap, bp.Minus(ap), /*asSegment=*/true);
DoCompare(distance - stroke->width / 2.0, stroke->zIndex, e.auxB); double depth = 0.5 * (camera.ProjectPoint3(e.a).z + camera.ProjectPoint3(e.b).z) ;
DoCompare(depth, distance - stroke->width / 2.0, stroke->zIndex, e.auxB);
} }
} }
@ -423,7 +426,8 @@ void ObjectPicker::DrawQuad(const Vector &a, const Vector &b, const Vector &c, c
void ObjectPicker::DrawPoint(const Vector &o, Canvas::hStroke hcs) { void ObjectPicker::DrawPoint(const Vector &o, Canvas::hStroke hcs) {
Stroke *stroke = strokes.FindById(hcs); Stroke *stroke = strokes.FindById(hcs);
double distance = point.DistanceTo(camera.ProjectPoint(o)) - stroke->width / 2; double distance = point.DistanceTo(camera.ProjectPoint(o)) - stroke->width / 2;
DoCompare(distance, stroke->zIndex); double depth = camera.ProjectPoint3(o).z;
DoCompare(depth, distance, stroke->zIndex);
} }
void ObjectPicker::DrawPolygon(const SPolygon &p, hFill hcf) { void ObjectPicker::DrawPolygon(const SPolygon &p, hFill hcf) {
@ -445,6 +449,7 @@ void ObjectPicker::DrawPixmap(std::shared_ptr<const Pixmap> pm,
} }
bool ObjectPicker::Pick(const std::function<void()> &drawFn) { bool ObjectPicker::Pick(const std::function<void()> &drawFn) {
minDepth = VERY_POSITIVE;
minDistance = VERY_POSITIVE; minDistance = VERY_POSITIVE;
maxZIndex = INT_MIN; maxZIndex = INT_MIN;

View File

@ -232,6 +232,7 @@ public:
double selRadius = 0.0; double selRadius = 0.0;
// Picking state. // Picking state.
double minDistance = 0.0; double minDistance = 0.0;
double minDepth = 1e10;
int maxZIndex = 0; int maxZIndex = 0;
uint32_t position = 0; uint32_t position = 0;
@ -257,7 +258,7 @@ public:
const Point2d &ta, const Point2d &tb, hFill hcf) override; const Point2d &ta, const Point2d &tb, hFill hcf) override;
void InvalidatePixmap(std::shared_ptr<const Pixmap> pm) override {} void InvalidatePixmap(std::shared_ptr<const Pixmap> pm) override {}
void DoCompare(double distance, int zIndex, int comparePosition = 0); void DoCompare(double depth, double distance, int zIndex, int comparePosition = 0);
void DoQuad(const Vector &a, const Vector &b, const Vector &c, const Vector &d, void DoQuad(const Vector &a, const Vector &b, const Vector &c, const Vector &d,
int zIndex, int comparePosition = 0); int zIndex, int comparePosition = 0);

View File

@ -727,6 +727,7 @@ public:
public: public:
int zIndex; int zIndex;
double distance; double distance;
double depth;
Selection selection; Selection selection;
}; };