Use custom rings comparator in BuildArea
continuous-integration/drone/push Build is passing Details

References #1122 in main branch (3.11.0dev)
gh-autolink
Sandro Santilli 2021-08-11 22:12:02 +02:00
parent f0d7ac29df
commit 2a8d88202d
2 changed files with 73 additions and 11 deletions

View File

@ -159,10 +159,9 @@ public:
static CoordinateSequence* atLeastNCoordinatesOrNothing(std::size_t n,
CoordinateSequence* c);
/// Return position of a Coordinate, or -1 if not found
///
/// FIXME: return std::size_t, using numeric_limits<std::size_t>::max
/// as 'not found' value.
/// Return position of a Coordinate
//
/// or numeric_limits<std::size_t>::max() if not found
///
static std::size_t indexOf(const Coordinate* coordinate,
const CoordinateSequence* cl);

View File

@ -66,6 +66,74 @@ struct Face {
}
};
static bool ringsEqualAnyDirection(const LinearRing* r1, const LinearRing* r2)
{
const CoordinateSequence *cs1 = r1->getCoordinatesRO();
const CoordinateSequence *cs2 = r2->getCoordinatesRO();
/* Check same number of points */
size_t npoints = cs1->size();
if ( npoints != cs2->size() )
{
return false;
}
if ( npoints == 0 ) return true; /* if empty, they are equal */
/* Check same envelope (probably better avoid, as it'd need to
* compute the envelope doing an additional scan for each) */
if ( ! r1->getEnvelopeInternal()->equals(r2->getEnvelopeInternal()) )
{
return false;
}
/* Pretend the rings had one less point, as the last one will be
* equal to the first one anyway */
--npoints;
const Coordinate& firstPoint = cs1->getAt(0);
size_t offset = CoordinateSequence::indexOf(&firstPoint, cs2);
if ( offset == std::numeric_limits<std::size_t>::max() ) return false;
bool equal = true;
/* Check equals forward (skip first point, we checked it alread) */
for (size_t i=1; i<npoints; ++i)
{
size_t j = ( i + offset ) % npoints;
const Coordinate& c1 = cs1->getAt(i);
const Coordinate& c2 = cs2->getAt(j);
if ( ! c1.equals(c2) ) {
equal = false;
break;
}
}
if ( equal ) return true;
/* Check equals backward (skip first point, we checked it already) */
equal = true;
for (size_t i=1; i<npoints; ++i)
{
size_t j;
if ( i <= offset ) {
j = offset - i;
} else {
j = npoints - ( i - offset );
}
const Coordinate& c1 = cs1->getAt(i);
const Coordinate& c2 = cs2->getAt(j);
if ( ! c1.equals(c2) ) {
equal = false;
break;
}
}
return equal;
}
static std::unique_ptr<Face> newFace(const geom::Polygon* p) {
auto f = std::unique_ptr<Face>(new Face());
f->poly = p;
@ -100,13 +168,8 @@ static void findFaceHoles(std::vector<std::unique_ptr<Face>>& faces) {
if( f2->parent ) {
continue; /* hole already assigned */
}
const auto f2er = f2->poly->getExteriorRing();
/* TODO: can be optimized as the ring would have the
* same vertices, possibly in different order.
* maybe comparing number of points could already be
* useful.
*/
if( f2er->equals(hole) ) {
const auto shell = f2->poly->getExteriorRing();
if( ringsEqualAnyDirection(shell, hole) ) {
f2->parent = f.get();
break;
}