Skip to content

Commit

Permalink
Merge pull request #368 from pklampros/fix_point_in_poly
Browse files Browse the repository at this point in the history
Fix point-in-polygon problems
  • Loading branch information
pklampros authored Jul 22, 2020
2 parents 936b115 + 06cca92 commit 680ff95
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 11 deletions.
3 changes: 2 additions & 1 deletion salaTest/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ set(salaTest_SRCS
testmapinfodata.cpp
testsalaprogram.cpp
testdxfp.cpp
testmapconversion.cpp)
testmapconversion.cpp
testpointinpoly.cpp)

include_directories("../ThirdParty/Catch" "../ThirdParty/FakeIt")

Expand Down
99 changes: 99 additions & 0 deletions salaTest/testpointinpoly.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// Copyright (C) 2020 Petros Koutsolampros

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

#include "catch.hpp"
#include "salalib/mapconverter.h"
#include "salalib/shapemap.h"

TEST_CASE("Test point in polygon in shapemap", "") {
// The problem this test was made to demostrate was that shapemaps with
// extended bounds tended to make the point-in-polygon more inaccurate.

std::unique_ptr<ShapeMap> shapeMap(new ShapeMap("Test ShapeMap"));

// main testing shape
shapeMap->makePolyShape(
{
Point2f(4.50, 5.75), //
Point2f(5.75, 5.50), //
Point2f(5.25, 4.75), //
Point2f(4.75, 4.50) //
},
false);

// points inside the polygon
std::vector<Point2f> pointsInsidePoly = {
Point2f(5.1250, 5.1250), //
Point2f(5.6345, 5.4522), //
Point2f(4.5884, 5.6616), //
Point2f(4.8049, 4.6123), //
Point2f(5.1673, 4.8437), //
Point2f(4.9441, 4.7368), //
Point2f(4.7476, 5.1495), //
Point2f(5.1005, 5.5024), //
Point2f(5.3960, 5.1943) //
};

// points outside (but very close to) the polygon
std::vector<Point2f> pointsOutsidePoly = {
Point2f(4.6951, 4.3877), //
Point2f(4.4116, 5.8384), //
Point2f(5.8655, 5.5478), //
Point2f(5.3327, 4.6563), //
Point2f(5.0559, 4.5132), //
Point2f(4.5024, 5.1005), //
Point2f(5.1495, 5.7476), //
Point2f(5.6040, 5.0557) //
};

for (Point2f point : pointsInsidePoly) {
REQUIRE(shapeMap->pointInPolyList(point)[0] == 0);
}

for (Point2f point : pointsOutsidePoly) {
REQUIRE(shapeMap->pointInPolyList(point).size() == 0);
}

// now extend the bounds

// first little extra rectangle to extend the map region to 0.25, 0.25
shapeMap->makePolyShape(
{
Point2f(0.25, 0.25), //
Point2f(0.50, 0.25), //
Point2f(0.50, 0.50), //
Point2f(0.25, 0.50) //
},
false);

// second little extra rectangle to extend the map region to 10.0, 10.0
shapeMap->makePolyShape(
{
Point2f(9.75, 9.75), //
Point2f(10.0, 9.75), //
Point2f(10.0, 10.0), //
Point2f(9.75, 10.0) //
},
false);


for (Point2f point : pointsInsidePoly) {
REQUIRE(shapeMap->pointInPolyList(point)[0] == 0);
}

for (Point2f point : pointsOutsidePoly) {
REQUIRE(shapeMap->pointInPolyList(point).size() == 0);
}
}
22 changes: 12 additions & 10 deletions salalib/shapemap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1717,8 +1717,8 @@ int ShapeMap::testPointInPoly(const Point2f &p, const ShapeRef &shape) const {
}
// check not an open shape (cannot be inside)
else if ((shape.m_tags & ShapeRef::SHAPE_OPEN) == 0) {
shapeIter = m_shapes.find(shape.m_shape_ref);
const SalaShape &poly = shapeIter->second;
auto tempShapeIter = m_shapes.find(shape.m_shape_ref);
const SalaShape &poly = tempShapeIter->second;
if (poly.m_region.contains_touch(p)) {
// next simplest, on the outside border:
int alpha = 0;
Expand Down Expand Up @@ -1790,7 +1790,7 @@ int ShapeMap::testPointInPoly(const Point2f &p, const ShapeRef &shape) const {
}
}
if (counter % 2 != 0 && alpha == 0) {
shapeIter = m_shapes.find(shape.m_shape_ref);
shapeIter = tempShapeIter;
}
}
// and now the pig -- it's somewhere in the middle of the poly:
Expand All @@ -1801,25 +1801,27 @@ int ShapeMap::testPointInPoly(const Point2f &p, const ShapeRef &shape) const {
depthmapX::addIfNotExists(testnodes, int(shape.m_polyrefs[j]));
}
PixelRef pix2 = pixelate(p);
const std::vector<ShapeRef> &pixelShapes =
m_pixel_shapes(static_cast<size_t>(pix2.y), static_cast<size_t>(pix2.x));
// bit of code duplication like this, but easier on params to this function:
pix2.move(PixelRef::NEGVERTICAL); // move pix2 down, search for this shape...
auto iter = std::find(pixelShapes.begin(), pixelShapes.end(), shape.m_shape_ref);
while (iter != pixelShapes.end()) {
const std::vector<ShapeRef> *pixelShapes =
&m_pixel_shapes(static_cast<size_t>(pix2.y), static_cast<size_t>(pix2.x));
// bit of code duplication like this, but easier on params to this function:
auto iter = std::find(pixelShapes->begin(), pixelShapes->end(), shape.m_shape_ref);
while (iter != pixelShapes->end()) {
for (size_t k = 0; k < iter->m_polyrefs.size(); k++) {
depthmapX::addIfNotExists(testnodes, int(iter->m_polyrefs[k]));
}
pix2.move(PixelRef::NEGVERTICAL); // move pix2 down, search for this shape...
pixelShapes = &m_pixel_shapes(static_cast<size_t>(pix2.y), static_cast<size_t>(pix2.x));
if (includes(pix2)) {
iter = std::find(pixelShapes.begin(), pixelShapes.end(), shape.m_shape_ref);
iter = std::find(pixelShapes->begin(), pixelShapes->end(), shape.m_shape_ref);
} else {
iter = pixelShapes.end();
iter = pixelShapes->end();
}
}
int alpha = 0;
int counter = 0;
int parity = -1;

for (j = 0; j < testnodes.size(); j++) {
Line lineb =
Line(poly.m_points[testnodes[j]], poly.m_points[((testnodes[j] + 1) % poly.m_points.size())]);
Expand Down

0 comments on commit 680ff95

Please sign in to comment.