Skip to content
Permalink
Browse files

Fix oriented minimum bounding box calculation is wrong in some cases

Fixes #36632
  • Loading branch information
nyalldawson committed May 25, 2020
1 parent 7e8d27e commit 97d098884a7889346739d61bd9048e9dcf942d11
@@ -7,7 +7,7 @@
<gml:boundedBy>
<gml:Box>
<gml:coord><gml:X>-2.056603773584904</gml:X><gml:Y>-3</gml:Y></gml:coord>
<gml:coord><gml:X>9.162955854126682</gml:X><gml:Y>6.489909219550769</gml:Y></gml:coord>
<gml:coord><gml:X>9.162955854126682</gml:X><gml:Y>6.088675623800386</gml:Y></gml:coord>
</gml:Box>
</gml:boundedBy>

@@ -25,26 +25,26 @@
</gml:featureMember>
<gml:featureMember>
<ogr:mbg_rect_field fid="mbg_rect_field.1">
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>5.24145873320538,-1.05451055662188 6.24145873320538,-2.05451055662188 7.24145873320538,-1.05451055662188 6.24145873320538,-0.054510556621882 5.24145873320538,-1.05451055662188</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>7.24145873320538,-1.05451055662188 7.24145873320538,-0.054510556621881 5.24145873320538,-0.054510556621881 5.24145873320538,-1.05451055662188 7.24145873320538,-1.05451055662188</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
<ogr:id>1</ogr:id>
<ogr:name>dd</ogr:name>
<ogr:width>1.414214</ogr:width>
<ogr:height>1.414214</ogr:height>
<ogr:angle>45.000000</ogr:angle>
<ogr:width>1.000000</ogr:width>
<ogr:height>2.000000</ogr:height>
<ogr:angle>90.000000</ogr:angle>
<ogr:area>2.000000</ogr:area>
<ogr:perimeter>5.656854</ogr:perimeter>
<ogr:perimeter>6.000000</ogr:perimeter>
</ogr:mbg_rect_field>
</gml:featureMember>
<gml:featureMember>
<ogr:mbg_rect_field fid="mbg_rect_field.2">
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>5.34748915030878,4.7278689643513 5.06593031585745,6.48990921955077 1.84418704183259,5.97510243323637 2.12574587628392,4.2130621780369 5.34748915030878,4.7278689643513</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>5.17255278310941,4.42360844529751 5.17255278310941,6.08867562380039 2.0,6.08867562380039 2.0,4.4236084452975 5.17255278310941,4.42360844529751</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
<ogr:id>2</ogr:id>
<ogr:name>bb</ogr:name>
<ogr:width>1.784394</ogr:width>
<ogr:height>3.262615</ogr:height>
<ogr:angle>80.921378</ogr:angle>
<ogr:area>5.821790</ogr:area>
<ogr:perimeter>10.094017</ogr:perimeter>
<ogr:width>1.665067</ogr:width>
<ogr:height>3.172553</ogr:height>
<ogr:angle>90.000000</ogr:angle>
<ogr:area>5.282514</ogr:area>
<ogr:perimeter>9.675240</ogr:perimeter>
</ogr:mbg_rect_field>
</gml:featureMember>
<gml:featureMember>
@@ -6,35 +6,35 @@
xmlns:gml="http://www.opengis.net/gml">
<gml:boundedBy>
<gml:Box>
<gml:coord><gml:X>-1</gml:X><gml:Y>-3.270344827586211</gml:Y></gml:coord>
<gml:coord><gml:X>10.0441379310345</gml:X><gml:Y>6.468552677345371</gml:Y></gml:coord>
<gml:coord><gml:X>-1</gml:X><gml:Y>-3.270344827586206</gml:Y></gml:coord>
<gml:coord><gml:X>10.04413793103448</gml:X><gml:Y>6.494117647058823</gml:Y></gml:coord>
</gml:Box>
</gml:boundedBy>

<gml:featureMember>
<ogr:oriented_bounds fid="polys.4">
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>6.0,-3.0 7.69811320754717,0.056603773584905 3.80943396226415,2.21698113207547 2.11132075471698,-0.839622641509436 6.0,-3.0</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>3.8,2.2 2.11847133757962,-0.882802547770694 6.0,-3.0 7.68152866242039,0.082802547770697 3.8,2.2</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
<ogr:intval>120</ogr:intval>
<ogr:floatval>-100291.43213</ogr:floatval>
<ogr:name xsi:nil="true"/>
<ogr:width>3.496629</ogr:width>
<ogr:height>4.448489</ogr:height>
<ogr:angle>119.054604</ogr:angle>
<ogr:area>15.554717</ogr:area>
<ogr:perimeter>15.890237</ogr:perimeter>
<ogr:width>3.511582</ogr:width>
<ogr:height>4.421401</ogr:height>
<ogr:angle>118.610460</ogr:angle>
<ogr:area>15.526115</ogr:area>
<ogr:perimeter>15.865967</ogr:perimeter>
</ogr:oriented_bounds>
</gml:featureMember>
<gml:featureMember>
<ogr:oriented_bounds fid="polys.1">
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>5.6332734,5.0792647 3.84029,4.4700214 4.2070166,3.3907567 6,4 5.6332734,5.0792647</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>4.0,4.0 4.67567567567567,3.05405405405406 6.07567567567567,4.05405405405405 5.4,5.0 4.0,4.0</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
<ogr:intval>-33</ogr:intval>
<ogr:floatval>0</ogr:floatval>
<ogr:name>Aaaaa</ogr:name>
<ogr:width>1.893665</ogr:width>
<ogr:height>1.139869</ogr:height>
<ogr:angle>161.232595</ogr:angle>
<ogr:area>2.158529</ogr:area>
<ogr:perimeter>6.067067</ogr:perimeter>
<ogr:width>1.162476</ogr:width>
<ogr:height>1.720465</ogr:height>
<ogr:angle>54.462322</ogr:angle>
<ogr:area>2.000000</ogr:area>
<ogr:perimeter>5.765883</ogr:perimeter>
</ogr:oriented_bounds>
</gml:featureMember>
<gml:featureMember>
@@ -52,7 +52,7 @@
</gml:featureMember>
<gml:featureMember>
<ogr:oriented_bounds fid="polys.3">
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>6.4,-3 9.6441379,-3.2703448 10.0441379,1.5296552 6.8,1.8 6.4,-3</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>6.4,-3.0 9.64413793103449,-3.27034482758621 10.0441379310345,1.52965517241379 6.8,1.8 6.4,-3.0</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
<ogr:intval>0</ogr:intval>
<ogr:floatval xsi:nil="true"/>
<ogr:name>ASDF</ogr:name>
@@ -65,28 +65,28 @@
</gml:featureMember>
<gml:featureMember>
<ogr:oriented_bounds fid="polys.2">
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>1.1679275,5.4220069 1.6,4.8 3.1065959,5.8465458 2.6745233,6.4685527 1.1679275,5.4220069</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>3.0,6.0 2.57647058823529,6.49411764705882 1.17647058823529,5.29411764705882 1.6,4.8 3.0,6.0</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
<ogr:intval xsi:nil="true"/>
<ogr:floatval>0.123</ogr:floatval>
<ogr:name>bbaaa</ogr:name>
<ogr:width>0.757350</ogr:width>
<ogr:height>1.834418</ogr:height>
<ogr:angle>55.214507</ogr:angle>
<ogr:area>1.389297</ogr:area>
<ogr:perimeter>5.183536</ogr:perimeter>
<ogr:width>0.650791</ogr:width>
<ogr:height>1.843909</ogr:height>
<ogr:angle>49.398705</ogr:angle>
<ogr:area>1.200000</ogr:area>
<ogr:perimeter>4.989401</ogr:perimeter>
</ogr:oriented_bounds>
</gml:featureMember>
<gml:featureMember>
<ogr:oriented_bounds fid="polys.5">
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>6.0,-3.0 7.69811320754717,0.056603773584905 3.80943396226415,2.21698113207547 2.11132075471698,-0.839622641509436 6.0,-3.0</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>3.8,2.2 2.11847133757962,-0.882802547770694 6.0,-3.0 7.68152866242039,0.082802547770697 3.8,2.2</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
<ogr:intval>2</ogr:intval>
<ogr:floatval>3.33</ogr:floatval>
<ogr:name>elim</ogr:name>
<ogr:width>3.496629</ogr:width>
<ogr:height>4.448489</ogr:height>
<ogr:angle>119.054604</ogr:angle>
<ogr:area>15.554717</ogr:area>
<ogr:perimeter>15.890237</ogr:perimeter>
<ogr:width>3.511582</ogr:width>
<ogr:height>4.421401</ogr:height>
<ogr:angle>118.610460</ogr:angle>
<ogr:area>15.526115</ogr:area>
<ogr:perimeter>15.865967</ogr:perimeter>
</ogr:oriented_bounds>
</gml:featureMember>
</ogr:FeatureCollection>
@@ -976,12 +976,12 @@ QgsGeometry QgsGeometry::orientedMinimumBoundingBox( double &area, double &angle
// get first point
hull.constGet()->nextVertex( vertexId, pt0 );
pt1 = pt0;
double prevAngle = 0.0;
double totalRotation = 0;
while ( hull.constGet()->nextVertex( vertexId, pt2 ) )
{
double currentAngle = QgsGeometryUtils::lineAngle( pt1.x(), pt1.y(), pt2.x(), pt2.y() );
double rotateAngle = 180.0 / M_PI * ( currentAngle - prevAngle );
prevAngle = currentAngle;
double rotateAngle = 180.0 / M_PI * currentAngle;
totalRotation += rotateAngle;

QTransform t = QTransform::fromTranslate( pt0.x(), pt0.y() );
t.rotate( rotateAngle );
@@ -995,12 +995,12 @@ QgsGeometry QgsGeometry::orientedMinimumBoundingBox( double &area, double &angle
{
minRect = bounds;
area = currentArea;
angle = 180.0 / M_PI * currentAngle;
angle = totalRotation;
width = bounds.width();
height = bounds.height();
}

pt1 = pt2;
pt1 = hull.constGet()->vertexAt( vertexId );
}

QgsGeometry minBounds = QgsGeometry::fromRect( minRect );
// Issue https://github.com/qgis/QGIS/issues/33532
geomTest = QgsGeometry::fromWkt( QStringLiteral( " Polygon ((264 -525, 248 -521, 244 -519, 233 -508, 231 -504, 210 -445, 196 -396, 180 -332, 178 -322, 176 -310, 174 -296, 174 -261, 176 -257, 178 -255, 183 -251, 193 -245, 197 -243, 413 -176, 439 -168, 447 -166, 465 -164, 548 -164, 552 -166, 561 -175, 567 -187, 602 -304, 618 -379, 618 -400, 616 -406, 612 -414, 606 -420, 587 -430, 575 -436, 547 -446, 451 -474, 437 -478, 321 -511, 283 -521, 275 -523, 266 -525, 264 -525)) " ) );
result = geomTest.orientedMinimumBoundingBox( );
QString resultTestWKT = QStringLiteral( "Polygon ((153.56814721430669124 -251.04910547836090018, 236.58928384252226351 -536.38483199428605985, 635.81698325140541783 -420.2257453523852746, 552.79584662318995925 -134.89001883646011493, 153.56814721430669124 -251.04910547836090018))" );
QCOMPARE( result.asWkt(), resultTestWKT );
QString resultTestWKT = QStringLiteral( "Polygon ((635.86 -420.08, 552.66 -134.85, 153.5 -251.27, 236.69 -536.51, 635.86 -420.08))" );
QCOMPARE( result.asWkt( 2 ), resultTestWKT );

}
void TestQgsGeometry::minimalEnclosingCircle()
@@ -4714,15 +4714,15 @@ def testMinimumOrientedBoundingBox(self):
# polygon
polygon = QgsGeometry.fromWkt('Polygon((-0.1 -1.3, 2.1 1, 3 2.8, 6.7 0.2, 3 -1.8, 0.3 -2.7, -0.1 -1.3))')
bbox, area, angle, width, height = polygon.orientedMinimumBoundingBox()
exp = 'Polygon ((2.63653329463248109 -4.65542585423934607, 6.70000000000000284 0.19999999999999485, 3.24436595086289614 3.09199224252241889, -0.81910075450462605 -1.76343361171692159, 2.63653329463248109 -4.65542585423934607))'
exp = 'Polygon ((-0.628 -1.9983, 2.9769 -4.724, 6.7 0.2, 3.095 2.9257, -0.628 -1.9983))'

result = bbox.asWkt()
result = bbox.asWkt(4)
self.assertTrue(compareWkt(result, exp, 0.00001),
"Oriented MBBR: mismatch Expected:\n{}\nGot:\n{}\n".format(exp, result))
self.assertAlmostEqual(area, 28.5300, places=3)
self.assertAlmostEqual(angle, 129.9257, places=3)
self.assertAlmostEqual(width, 6.3314, places=3)
self.assertAlmostEqual(height, 4.5061, places=3)
self.assertAlmostEqual(area, 27.89886071158214, places=3)
self.assertAlmostEqual(angle, 37.09283729704157, places=3)
self.assertAlmostEqual(width, 4.519421040409892, places=3)
self.assertAlmostEqual(height, 6.173105019896937, places=3)

def testOrthogonalize(self):
empty = QgsGeometry()

0 comments on commit 97d0988

Please sign in to comment.
You can’t perform that action at this time.