1 /***************************************************************************
2 testqgsellipse.cpp
3 --------------------------------------
4 Date : August 2021
5 Copyright : (C) 2021 by Loïc Bartoletti
6 Email : loic dot bartoletti at oslandia dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15 #include "qgstest.h"
16 #include <QObject>
17 #include <QString>
18
19 #include "qgsellipse.h"
20 #include "qgsgeometryutils.h"
21 #include "qgslinestring.h"
22 #include "qgspoint.h"
23
24 #include "testgeometryutils.h"
25
26 class TestQgsEllipse: public QObject
27 {
28 Q_OBJECT
29 private slots:
30 void ellipse();
31 };
32
ellipse()33 void TestQgsEllipse::ellipse()
34 {
35 //test constructors
36 QgsEllipse elp1;
37 QVERIFY( elp1.center().isEmpty() );
38 QCOMPARE( elp1.semiMajorAxis(), 0.0 );
39 QCOMPARE( elp1.semiMinorAxis(), 0.0 );
40 QCOMPARE( elp1.azimuth(), 90.0 );
41 QVERIFY( elp1.isEmpty() );
42
43 QgsEllipse elp2( QgsPoint( 5, 10 ), 3, 2 );
44 QVERIFY( elp2.center() == QgsPoint( 5, 10 ) );
45 QCOMPARE( elp2.semiMajorAxis(), 3.0 );
46 QCOMPARE( elp2.semiMinorAxis(), 2.0 );
47 QCOMPARE( elp2.azimuth(), 90.0 );
48 QVERIFY( !elp2.isEmpty() );
49
50 QgsEllipse elp3( QgsPoint( 5, 10 ), 3, 2, 45 );
51 QVERIFY( elp3.center() == QgsPoint( 5, 10 ) );
52 QCOMPARE( elp3.semiMajorAxis(), 3.0 );
53 QCOMPARE( elp3.semiMinorAxis(), 2.0 );
54 QCOMPARE( elp3.azimuth(), 45.0 );
55 QVERIFY( !elp3.isEmpty() );
56
57 QgsEllipse elp4( QgsPoint( 5, 10 ), 2, 3, 45 );
58 QVERIFY( elp4.center() == QgsPoint( 5, 10 ) );
59 QCOMPARE( elp4.semiMajorAxis(), 3.0 );
60 QCOMPARE( elp4.semiMinorAxis(), 2.0 );
61 QCOMPARE( elp4.azimuth(), 135.0 );
62 QVERIFY( !elp4.isEmpty() );
63
64 //test toString
65 QCOMPARE( elp1.toString(), QString( "Empty" ) );
66 QCOMPARE( elp2.toString(), QString( "Ellipse (Center: Point (5 10), Semi-Major Axis: 3, Semi-Minor Axis: 2, Azimuth: 90)" ) );
67 QCOMPARE( elp3.toString(), QString( "Ellipse (Center: Point (5 10), Semi-Major Axis: 3, Semi-Minor Axis: 2, Azimuth: 45)" ) );
68 QCOMPARE( elp4.toString(), QString( "Ellipse (Center: Point (5 10), Semi-Major Axis: 3, Semi-Minor Axis: 2, Azimuth: 135)" ) );
69
70 //test equality operator
71 QCOMPARE( QgsEllipse().isEmpty(), QgsEllipse( QgsPoint(), 0, 0, 90 ).isEmpty() );
72 QVERIFY( !( QgsEllipse() == QgsEllipse( QgsPoint( 0, 0 ), 0, 0, 0.0005 ) ) );
73 QVERIFY( elp2 == QgsEllipse( QgsPoint( 5, 10 ), 2, 3, 0 ) );
74 QVERIFY( elp2 != elp3 );
75 QVERIFY( elp3 != elp4 );
76 QVERIFY( elp4 == QgsEllipse( QgsPoint( 5, 10 ), 3, 2, 90 + 45 ) );
77
78 //test setter and getter
79 elp1.setAzimuth( 45 );
80 QCOMPARE( elp1.azimuth(), 45.0 );
81
82 elp1.setSemiMajorAxis( 50 );
83 QCOMPARE( elp1.semiMajorAxis(), 50.0 );
84
85 // axis_b > axis_a
86 elp1.setSemiMinorAxis( 70 );
87 QCOMPARE( elp1.semiMajorAxis(), 70.0 );
88 QCOMPARE( elp1.semiMinorAxis(), 50.0 );
89 // axis_b < axis_a
90 elp1.setSemiMinorAxis( 3 );
91 QCOMPARE( elp1.semiMinorAxis(), 3.0 );
92 QCOMPARE( elp1.semiMajorAxis(), 70.0 );
93
94 elp1.setSemiMajorAxis( 2 );
95 QCOMPARE( elp1.semiMinorAxis(), 2.0 );
96 QCOMPARE( elp1.semiMajorAxis(), 3.0 );
97
98 elp1.setCenter( QgsPoint( 5, 10 ) );
99 QVERIFY( elp1.center() == QgsPoint( 5, 10 ) );
100 QVERIFY( elp1.rcenter() == QgsPoint( 5, 10 ) );
101 elp1.rcenter() = QgsPoint( 25, 310 );
102 QVERIFY( elp1.center() == QgsPoint( 25, 310 ) );
103
104 //test "alt" constructors
105 // fromExtent
106 QgsEllipse elp_alt = QgsEllipse( QgsPoint( 2.5, 5 ), 2.5, 5 );
107 QVERIFY( QgsEllipse().fromExtent( QgsPoint( 0, 0 ), QgsPoint( 5, 10 ) ) == elp_alt );
108 QVERIFY( QgsEllipse().fromExtent( QgsPoint( 5, 10 ), QgsPoint( 0, 0 ) ) == elp_alt );
109 QVERIFY( QgsEllipse().fromExtent( QgsPoint( 5, 0 ), QgsPoint( 0, 10 ) ) == elp_alt );
110 QVERIFY( QgsEllipse().fromExtent( QgsPoint( -5, 0 ), QgsPoint( 0, 10 ) ) != elp_alt );
111 // fromCenterPoint
112 QVERIFY( QgsEllipse().fromCenterPoint( QgsPoint( 2.5, 5 ), QgsPoint( 5, 10 ) ) == elp_alt );
113 QVERIFY( QgsEllipse().fromCenterPoint( QgsPoint( 2.5, 5 ), QgsPoint( -0, 0 ) ) == elp_alt );
114 QVERIFY( QgsEllipse().fromCenterPoint( QgsPoint( 2.5, 5 ), QgsPoint( 0, -10 ) ) != elp_alt );
115 // fromCenter2Points
116 QVERIFY( QgsEllipse().fromCenter2Points( QgsPoint( 2.5, 5 ), QgsPoint( 2.5, 0 ), QgsPoint( 7.5, 5 ) ) ==
117 QgsEllipse( QgsPoint( 2.5, 5 ), 5, 5, 180 ) );
118 QVERIFY( QgsEllipse().fromCenter2Points( QgsPoint( 2.5, 5 ), QgsPoint( 2.5, 7.5 ), QgsPoint( 7.5, 5 ) ) != elp_alt ); //same ellipse with different azimuth
119 QVERIFY( QgsEllipse().fromCenter2Points( QgsPoint( 2.5, 5 ), QgsPoint( 2.5, 2.5 ), QgsPoint( 7.5, 5 ) ) != elp_alt ); //same ellipse with different azimuth
120 QVERIFY( QgsEllipse().fromCenter2Points( QgsPoint( 2.5, 5 ), QgsPoint( 2.5, 0 ), QgsPoint( 5, 5 ) ) == elp_alt );
121 QVERIFY( QgsEllipse().fromCenter2Points( QgsPoint( 5, 10 ), QgsPoint( 5, 10 ).project( 3, 45 ), QgsPoint( 5, 10 ).project( 2, 90 + 45 ) ) ==
122 QgsEllipse( QgsPoint( 5, 10 ), 3, 2, 45 ) );
123
124 // fromFoci
125 // horizontal
126 QgsEllipse elp_hor = QgsEllipse().fromFoci( QgsPoint( -4, 0 ), QgsPoint( 4, 0 ), QgsPoint( 0, 4 ) );
127 QVERIFY( QgsEllipse( QgsPoint( 0, 0 ), std::sqrt( 32.0 ), std::sqrt( 16.0 ), 90.0 ) == elp_hor );
128 QGSCOMPARENEARPOINT( QgsPoint( 4, 0 ), elp_hor.foci().at( 0 ), 1e-8 );
129 QGSCOMPARENEARPOINT( QgsPoint( -4, 0 ), elp_hor.foci().at( 1 ), 1e-8 );
130 elp_hor = QgsEllipse().fromFoci( QgsPoint( 4, 0 ), QgsPoint( -4, 0 ), QgsPoint( 0, 4 ) );
131 QVERIFY( QgsEllipse( QgsPoint( 0, 0 ), std::sqrt( 32.0 ), std::sqrt( 16.0 ), 270.0 ) == elp_hor );
132 QGSCOMPARENEARPOINT( QgsPoint( -4, 0 ), elp_hor.foci().at( 0 ), 1e-8 );
133 QGSCOMPARENEARPOINT( QgsPoint( 4, 0 ), elp_hor.foci().at( 1 ), 1e-8 );
134
135 // vertical
136 QgsEllipse elp_ver = QgsEllipse().fromFoci( QgsPoint( 45, -15 ), QgsPoint( 45, 10 ), QgsPoint( 55, 0 ) );
137 QVERIFY( QgsEllipse( QgsPoint( 45, -2.5 ), 16.084946, 10.123017725, 0.0 ) == elp_ver );
138 elp_ver = QgsEllipse().fromFoci( QgsPoint( 45, 10 ), QgsPoint( 45, -15 ), QgsPoint( 55, 0 ) );
139 QVERIFY( QgsEllipse( QgsPoint( 45, -2.5 ), 16.084946, 10.123017725, 180.0 ) == elp_ver );
140 QGSCOMPARENEARPOINT( QgsPoint( 45, -15 ), elp_ver.foci().at( 0 ), 1e-8 );
141 QGSCOMPARENEARPOINT( QgsPoint( 45, 10 ), elp_ver.foci().at( 1 ), 1e-8 );
142 // oriented
143 // first quadrant
144 QgsEllipse elp_ori = QgsEllipse().fromFoci( QgsPoint( 10, 10 ), QgsPoint( 25, 20 ), QgsPoint( 15, 20 ) );
145 QVERIFY( QgsEllipse( QgsPoint( 17.5, 15.0 ), 10.5901699437, 5.55892970251, 90.0 - 33.690067526 ) == elp_ori );
146 QGSCOMPARENEARPOINT( QgsPoint( 25, 20 ), elp_ori.foci().at( 0 ), 1e-8 );
147 QGSCOMPARENEARPOINT( QgsPoint( 10, 10 ), elp_ori.foci().at( 1 ), 1e-8 );
148 // second quadrant
149 elp_ori = QgsEllipse().fromFoci( QgsPoint( 10, 10 ), QgsPoint( 5, 20 ), QgsPoint( 15, 20 ) );
150 QVERIFY( QgsEllipse( QgsPoint( 7.5, 15.0 ), 10.5901699437, 8.99453719974, 360 - 26.56505117 ) == elp_ori );
151 QGSCOMPARENEARPOINT( QgsPoint( 5, 20 ), elp_ori.foci().at( 0 ), 1e-8 );
152 QGSCOMPARENEARPOINT( QgsPoint( 10, 10 ), elp_ori.foci().at( 1 ), 1e-8 );
153 // third quadrant
154 elp_ori = QgsEllipse().fromFoci( QgsPoint( 10, 10 ), QgsPoint( 5, -5 ), QgsPoint( 15, 20 ) );
155 QVERIFY( QgsEllipse( QgsPoint( 7.5, 2.5 ), 19.0530819616, 17.3355107289893, 198.434948822922 ) == elp_ori );
156 QGSCOMPARENEARPOINT( QgsPoint( 10, 10 ), elp_ori.foci().at( 1 ), 1e-8 );
157 QGSCOMPARENEARPOINT( QgsPoint( 5, -5 ), elp_ori.foci().at( 0 ), 1e-8 );
158 // fourth quadrant
159 elp_ori = QgsEllipse().fromFoci( QgsPoint( 10, 10 ), QgsPoint( 25, -5 ), QgsPoint( 15, 20 ) );
160 QVERIFY( QgsEllipse( QgsPoint( 17.5, 2.5 ), 19.0530819616, 15.82782146, 135 ) == elp_ori );
161 QGSCOMPARENEARPOINT( QgsPoint( 25, -5 ), elp_ori.foci().at( 0 ), 1e-8 );
162 QGSCOMPARENEARPOINT( QgsPoint( 10, 10 ), elp_ori.foci().at( 1 ), 1e-8 );
163
164 // test quadrant
165 QgsEllipse elpq( QgsPoint( 5, 10 ), 3, 2, 45 );
166 QgsPointSequence q = elpq.quadrant();
167 QGSCOMPARENEARPOINT( q.at( 0 ), QgsPoint( 7.1213, 12.1213 ), 0.001 );
168 QGSCOMPARENEARPOINT( q.at( 3 ), QgsPoint( 3.5858, 11.4142 ), 0.001 );
169 QGSCOMPARENEARPOINT( q.at( 2 ), QgsPoint( 2.8787, 7.8787 ), 0.001 );
170 QGSCOMPARENEARPOINT( q.at( 1 ), QgsPoint( 6.4142, 8.5858 ), 0.001 );
171
172 elpq = QgsEllipse( QgsPoint( 0, 0 ), 5, 2, 90 );
173 q.clear();
174 q = elpq.quadrant();
175 QCOMPARE( q.at( 3 ), QgsPoint( 0, 2 ) );
176 QCOMPARE( q.at( 0 ), QgsPoint( 5, 0 ) );
177 QCOMPARE( q.at( 1 ), QgsPoint( 0, -2 ) );
178 QCOMPARE( q.at( 2 ), QgsPoint( -5, 0 ) );
179
180 elpq = QgsEllipse( QgsPoint( QgsWkbTypes::PointZM, 0, 0, 123, 321 ), 5, 2, 0 );
181 q.clear();
182 q = elpq.quadrant();
183 QCOMPARE( q.at( 0 ), QgsPoint( QgsWkbTypes::PointZM, 0, 5, 123, 321 ) );
184 QCOMPARE( q.at( 3 ), QgsPoint( QgsWkbTypes::PointZM, -2, 0, 123, 321 ) );
185 QCOMPARE( q.at( 2 ), QgsPoint( QgsWkbTypes::PointZM, 0, -5, 123, 321 ) );
186 QCOMPARE( q.at( 1 ), QgsPoint( QgsWkbTypes::PointZM, 2, 0, 123, 321 ) );
187
188 elpq = QgsEllipse( QgsPoint( 0, 0 ), 2.5, 2, 315 );
189 q.clear();
190 q = elpq.quadrant();
191 QGSCOMPARENEARPOINT( q.at( 1 ), QgsPoint( 1.4142, 1.4142 ), 0.001 );
192 QGSCOMPARENEARPOINT( q.at( 2 ), QgsPoint( 1.7678, -1.7678 ), 0.001 );
193 QGSCOMPARENEARPOINT( q.at( 3 ), QgsPoint( -1.4142, -1.4142 ), 0.001 );
194 QGSCOMPARENEARPOINT( q.at( 0 ), QgsPoint( -1.7678, 1.7678 ), 0.001 );
195
196 elpq = QgsEllipse( QgsPoint( 0, 0 ), 5, 2.5, 45 );
197 q.clear();
198 q = elpq.quadrant();
199 QGSCOMPARENEARPOINT( q.at( 3 ), QgsPoint( -1.7678, 1.7678 ), 0.001 );
200 QGSCOMPARENEARPOINT( q.at( 0 ), QgsPoint( 3.5355, 3.5355 ), 0.001 );
201 QGSCOMPARENEARPOINT( q.at( 1 ), QgsPoint( 1.7678, -1.7678 ), 0.001 );
202 QGSCOMPARENEARPOINT( q.at( 2 ), QgsPoint( -3.5355, -3.5355 ), 0.001 );
203
204 //test conversion
205 // points
206 QgsPointSequence pts;
207 pts = QgsEllipse( QgsPoint( 0, 0 ), 5, 2, 0 ).points( 4 );
208 q = QgsEllipse( QgsPoint( 0, 0 ), 5, 2, 0 ).quadrant();
209 QCOMPARE( pts.length(), 4 );
210 QGSCOMPARENEARPOINT( q.at( 0 ), pts.at( 0 ), 2 );
211 QGSCOMPARENEARPOINT( q.at( 1 ), pts.at( 1 ), 2 );
212 QGSCOMPARENEARPOINT( q.at( 2 ), pts.at( 2 ), 2 );
213 QGSCOMPARENEARPOINT( q.at( 3 ), pts.at( 3 ), 2 );
214
215 QVERIFY( QgsEllipse( QgsPoint( 0, 0 ), 5, 2, 0 ).points( 2 ).isEmpty() ); // segments too low
216
217 // linestring
218 std::unique_ptr< QgsLineString > l( new QgsLineString() );
219
220 l.reset( QgsEllipse( QgsPoint( 0, 0 ), 5, 2, 0 ).toLineString( 2 ) );
221 QVERIFY( l->isEmpty() ); // segments too low
222
223 l.reset( QgsEllipse( QgsPoint( 0, 0 ), 5, 2, 0 ).toLineString( 4 ) );
224 QCOMPARE( l->numPoints(), 5 ); // closed linestring
225 QgsPointSequence pts_l;
226 l->points( pts_l );
227 pts_l.pop_back();
228 QCOMPARE( pts, pts_l );
229
230 // polygon
231 std::unique_ptr< QgsPolygon > p1( new QgsPolygon() );
232
233 p1.reset( QgsEllipse( QgsPoint( 0, 0 ), 5, 2, 0 ).toPolygon( 2 ) );
234 QVERIFY( p1->isEmpty() ); // segments too low
235
236 p1.reset( QgsEllipse( QgsPoint( 0, 0 ), 5, 2, 0 ).toPolygon( 4 ) );
237 q = QgsEllipse( QgsPoint( 0, 0 ), 5, 2, 0 ).quadrant();
238 QCOMPARE( p1->vertexAt( QgsVertexId( 0, 0, 0 ) ), q.at( 0 ) );
239 QCOMPARE( p1->vertexAt( QgsVertexId( 0, 0, 1 ) ), q.at( 1 ) );
240 QCOMPARE( p1->vertexAt( QgsVertexId( 0, 0, 2 ) ), q.at( 2 ) );
241 QCOMPARE( p1->vertexAt( QgsVertexId( 0, 0, 3 ) ), q.at( 3 ) );
242 QCOMPARE( p1->vertexAt( QgsVertexId( 0, 0, 4 ) ), q.at( 0 ) );
243 QCOMPARE( 0, p1->numInteriorRings() );
244 QCOMPARE( 5, p1->exteriorRing()->numPoints() );
245
246 p1.reset( QgsEllipse( QgsPoint( 0, 0 ), 5, 2, 90 ).toPolygon( 4 ) );
247 q = QgsEllipse( QgsPoint( 0, 0 ), 5, 2, 90 ).quadrant();
248 QCOMPARE( p1->vertexAt( QgsVertexId( 0, 0, 0 ) ), q.at( 0 ) );
249 QCOMPARE( p1->vertexAt( QgsVertexId( 0, 0, 1 ) ), q.at( 1 ) );
250 QCOMPARE( p1->vertexAt( QgsVertexId( 0, 0, 2 ) ), q.at( 2 ) );
251 QCOMPARE( p1->vertexAt( QgsVertexId( 0, 0, 3 ) ), q.at( 3 ) );
252 QCOMPARE( p1->vertexAt( QgsVertexId( 0, 0, 4 ) ), q.at( 0 ) );
253 QCOMPARE( 0, p1->numInteriorRings() );
254 QCOMPARE( 5, p1->exteriorRing()->numPoints() );
255
256 p1.reset( elpq.toPolygon( 4 ) );
257 q = elpq.quadrant();
258 QCOMPARE( p1->vertexAt( QgsVertexId( 0, 0, 0 ) ), q.at( 0 ) );
259 QCOMPARE( p1->vertexAt( QgsVertexId( 0, 0, 1 ) ), q.at( 1 ) );
260 QCOMPARE( p1->vertexAt( QgsVertexId( 0, 0, 2 ) ), q.at( 2 ) );
261 QCOMPARE( p1->vertexAt( QgsVertexId( 0, 0, 3 ) ), q.at( 3 ) );
262 QCOMPARE( p1->vertexAt( QgsVertexId( 0, 0, 4 ) ), q.at( 0 ) );
263 QCOMPARE( 0, p1->numInteriorRings() );
264 QCOMPARE( 5, p1->exteriorRing()->numPoints() );
265
266 // oriented bounding box
267 std::unique_ptr< QgsPolygon > ombb( QgsEllipse().orientedBoundingBox() );
268 QVERIFY( ombb->isEmpty() );
269
270 elpq = QgsEllipse( QgsPoint( 0, 0 ), 5, 2 );
271 ombb.reset( new QgsPolygon() );
272 QgsLineString *ext = new QgsLineString();
273 ext->setPoints( QgsPointSequence() << QgsPoint( 5, 2 ) << QgsPoint( 5, -2 ) << QgsPoint( -5, -2 ) << QgsPoint( -5, 2 ) );
274 ombb->setExteriorRing( ext );
275 std::unique_ptr< QgsPolygon >ombb2( elpq.orientedBoundingBox() );
276 QCOMPARE( ombb->asWkt( 2 ), ombb2->asWkt( 2 ) );
277
278 elpq = QgsEllipse( QgsPoint( 0, 0 ), 5, 2.5, 45 );
279 ombb.reset( elpq.orientedBoundingBox() );
280 QGSCOMPARENEARPOINT( ombb->exteriorRing()->vertexAt( QgsVertexId( 0, 0, 0 ) ), QgsPoint( 1.7678, 5.3033 ), 0.0001 );
281 QGSCOMPARENEARPOINT( ombb->exteriorRing()->vertexAt( QgsVertexId( 0, 0, 1 ) ), QgsPoint( 5.3033, 1.7678 ), 0.0001 );
282 QGSCOMPARENEARPOINT( ombb->exteriorRing()->vertexAt( QgsVertexId( 0, 0, 2 ) ), QgsPoint( -1.7678, -5.3033 ), 0.0001 );
283 QGSCOMPARENEARPOINT( ombb->exteriorRing()->vertexAt( QgsVertexId( 0, 0, 3 ) ), QgsPoint( -5.3033, -1.7678 ), 0.0001 );
284
285 elpq = QgsEllipse( QgsPoint( 0, 0 ), 5, 2.5, 315 );
286 ombb.reset( elpq.orientedBoundingBox() );
287 QGSCOMPARENEARPOINT( ombb->exteriorRing()->vertexAt( QgsVertexId( 0, 0, 0 ) ), QgsPoint( -5.3033, 1.7678 ), 0.0001 );
288 QGSCOMPARENEARPOINT( ombb->exteriorRing()->vertexAt( QgsVertexId( 0, 0, 1 ) ), QgsPoint( -1.7678, 5.3033 ), 0.0001 );
289 QGSCOMPARENEARPOINT( ombb->exteriorRing()->vertexAt( QgsVertexId( 0, 0, 2 ) ), QgsPoint( 5.3033, -1.7678 ), 0.0001 );
290 QGSCOMPARENEARPOINT( ombb->exteriorRing()->vertexAt( QgsVertexId( 0, 0, 3 ) ), QgsPoint( 1.7678, -5.3033 ), 0.0001 );
291
292 // bounding box
293 QCOMPARE( QgsEllipse().boundingBox(), QgsRectangle() );
294 ombb.reset( QgsEllipse( QgsPoint( 0, 0 ), 5, 2 ).orientedBoundingBox() );
295 QCOMPARE( QgsEllipse( QgsPoint( 0, 0 ), 5, 2 ).boundingBox(), ombb->boundingBox() );
296 QCOMPARE( QgsEllipse( QgsPoint( 0, 0 ), 5, 5 ).boundingBox(), QgsRectangle( QgsPointXY( -5, -5 ), QgsPointXY( 5, 5 ) ) );
297 QCOMPARE( QgsEllipse( QgsPoint( 0, 0 ), 5, 5, 60 ).boundingBox(), QgsRectangle( QgsPointXY( -5, -5 ), QgsPointXY( 5, 5 ) ) );
298 QCOMPARE( QgsEllipse( QgsPoint( 0, 0 ), 13, 9, 45 ).boundingBox().toString( 4 ).toStdString(), QgsRectangle( QgsPointXY( -11.1803, -11.1803 ), QgsPointXY( 11.1803, 11.1803 ) ).toString( 4 ).toStdString() );
299 QCOMPARE( QgsEllipse( QgsPoint( 0, 0 ), 13, 9, 60 ).boundingBox().toString( 4 ).toStdString(), QgsRectangle( QgsPointXY( -12.12436, -10.14889 ), QgsPointXY( 12.12436, 10.14889 ) ).toString( 4 ).toStdString() );
300 QCOMPARE( QgsEllipse( QgsPoint( 0, 0 ), 13, 9, 60 + 90 ).boundingBox().toString( 4 ).toStdString(), QgsRectangle( QgsPointXY( -10.14889, -12.12436 ), QgsPointXY( 10.14889, 12.12436 ) ).toString( 4 ).toStdString() );
301 QCOMPARE( QgsEllipse( QgsPoint( 0, 0 ), 13, 9, 300 ).boundingBox().toString( 4 ).toStdString(), QgsRectangle( QgsPointXY( -12.12436, -10.14889 ), QgsPointXY( 12.12436, 10.14889 ) ).toString( 4 ).toStdString() );
302 QCOMPARE( QgsEllipse( QgsPoint( 0, 0 ), 13, 9, 300 - 90 ).boundingBox().toString( 4 ).toStdString(), QgsRectangle( QgsPointXY( -10.14889, -12.12436 ), QgsPointXY( 10.14889, 12.12436 ) ).toString( 4 ).toStdString() );
303
304 // focus
305 QCOMPARE( QgsEllipse().fromFoci( QgsPoint( -4, 0 ), QgsPoint( 4, 0 ), QgsPoint( 0, 4 ) ).focusDistance(), 4.0 );
306 QGSCOMPARENEAR( QgsEllipse().fromFoci( QgsPoint( 10, 10 ), QgsPoint( 25, 20 ), QgsPoint( 15, 20 ) ).focusDistance(), 9.01388, 0.0001 );
307
308 // eccentricity
309 QCOMPARE( QgsEllipse().fromFoci( QgsPoint( -4, 0 ), QgsPoint( 4, 0 ), QgsPoint( 0, 4 ) ).eccentricity(), 0.7071067811865475 );
310 QCOMPARE( QgsEllipse( QgsPoint( 0, 0 ), 3, 3 ).eccentricity(), 0.0 );
311 QVERIFY( std::isnan( QgsEllipse().eccentricity() ) );
312
313 // area
314 QGSCOMPARENEAR( 31.4159, QgsEllipse( QgsPoint( 0, 0 ), 5, 2, 0 ).area(), 0.0001 );
315 // perimeter
316 p1.reset( QgsEllipse( QgsPoint( 0, 0 ), 5, 2, 45 ).toPolygon( 10000 ) );
317 QGSCOMPARENEAR( QgsEllipse( QgsPoint( 0, 0 ), 5, 2, 45 ).perimeter(), p1->perimeter(), 0.001 );
318
319 }
320
321
322 QGSTEST_MAIN( TestQgsEllipse )
323 #include "testqgsellipse.moc"
324