1 /**
2 * SFCGAL
3 *
4 * Copyright (C) 2012-2013 Oslandia <infos@oslandia.com>
5 * Copyright (C) 2012-2013 IGN (http://www.ign.fr)
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include <SFCGAL/Coordinate.h>
22
23 #include <SFCGAL/Kernel.h>
24 #include <SFCGAL/Exception.h>
25 #include <SFCGAL/numeric.h>
26
27 namespace SFCGAL {
28
29 ///
30 ///
31 ///
Coordinate()32 Coordinate::Coordinate():
33 _storage( Coordinate::Empty() )
34 {
35 }
36
37 ///
38 ///
39 ///
Coordinate(const Kernel::FT & x,const Kernel::FT & y)40 Coordinate::Coordinate( const Kernel::FT& x, const Kernel::FT& y ):
41 _storage( Kernel::Point_2( x, y ) )
42 {
43
44 }
45
46 ///
47 ///
48 ///
Coordinate(const Kernel::FT & x,const Kernel::FT & y,const Kernel::FT & z)49 Coordinate::Coordinate( const Kernel::FT& x, const Kernel::FT& y, const Kernel::FT& z ):
50 _storage( Kernel::Point_3( x, y, z ) )
51 {
52
53 }
54
55
56 ///
57 ///
58 ///
Coordinate(const double & x,const double & y)59 Coordinate::Coordinate( const double& x, const double& y )
60 {
61 if ( !std::isfinite( x ) || !std::isfinite( y ) ) {
62 BOOST_THROW_EXCEPTION( NonFiniteValueException( "cannot create coordinate with non finite value" ) );
63 }
64
65 _storage = Kernel::Point_2( x, y );
66 }
67
68 ///
69 ///
70 ///
Coordinate(const double & x,const double & y,const double & z)71 Coordinate::Coordinate( const double& x, const double& y, const double& z )
72 {
73 if ( !std::isfinite( x ) || !std::isfinite( y ) || !std::isfinite( z ) ) {
74 BOOST_THROW_EXCEPTION( NonFiniteValueException( "cannot create coordinate with non finite value" ) );
75 }
76
77 _storage = Kernel::Point_3( x, y, z );
78 }
79
80 ///
81 ///
82 ///
Coordinate(const Kernel::Point_2 & other)83 Coordinate::Coordinate( const Kernel::Point_2& other ):
84 _storage( other )
85 {
86
87 }
88
89 ///
90 ///
91 ///
Coordinate(const Kernel::Point_3 & other)92 Coordinate::Coordinate( const Kernel::Point_3& other ):
93 _storage( other )
94 {
95
96 }
97
98
99 ///
100 ///
101 ///
Coordinate(const Coordinate & other)102 Coordinate::Coordinate( const Coordinate& other ):
103 _storage( other._storage )
104 {
105
106 }
107
108 ///
109 ///
110 ///
operator =(const Coordinate & other)111 Coordinate& Coordinate::operator = ( const Coordinate& other )
112 {
113 _storage = other._storage;
114 return *this ;
115 }
116
117 ///
118 ///
119 ///
~Coordinate()120 Coordinate::~Coordinate()
121 {
122
123 }
124
125
126 class CoordinateDimensionVisitor : public boost::static_visitor<int> {
127 public:
operator ()(const Coordinate::Empty &) const128 int operator()( const Coordinate::Empty& ) const {
129 return 0;
130 }
operator ()(const Kernel::Point_2 &) const131 int operator()( const Kernel::Point_2& ) const {
132 return 2;
133 }
operator ()(const Kernel::Point_3 &) const134 int operator()( const Kernel::Point_3& ) const {
135 return 3;
136 }
137 };
138
139
140 ///
141 ///
142 ///
coordinateDimension() const143 int Coordinate::coordinateDimension() const
144 {
145 CoordinateDimensionVisitor visitor;
146 return boost::apply_visitor( visitor, _storage );
147 }
148
149
150 ///
151 ///
152 ///
isEmpty() const153 bool Coordinate::isEmpty() const
154 {
155 return _storage.which() == 0;
156 }
157
158 ///
159 ///
160 ///
is3D() const161 bool Coordinate::is3D() const
162 {
163 return _storage.which() == 2;
164 }
165
166 class GetXVisitor : public boost::static_visitor<Kernel::FT> {
167 public:
operator ()(const Coordinate::Empty &) const168 Kernel::FT operator()( const Coordinate::Empty& ) const {
169 BOOST_THROW_EXCEPTION( Exception( "trying to get an empty coordinate x value" ) );
170 return 0;
171 }
operator ()(const Kernel::Point_2 & storage) const172 Kernel::FT operator()( const Kernel::Point_2& storage ) const {
173 return storage.x();
174 }
operator ()(const Kernel::Point_3 & storage) const175 Kernel::FT operator()( const Kernel::Point_3& storage ) const {
176 return storage.x();
177 }
178 };
179
180 ///
181 ///
182 ///
x() const183 Kernel::FT Coordinate::x() const
184 {
185 GetXVisitor visitor;
186 return boost::apply_visitor( visitor, _storage );
187 }
188
189 class GetYVisitor : public boost::static_visitor<Kernel::FT> {
190 public:
operator ()(const Coordinate::Empty &) const191 Kernel::FT operator()( const Coordinate::Empty& ) const {
192 BOOST_THROW_EXCEPTION( Exception( "trying to get an empty coordinate y value" ) );
193 return 0;
194 }
operator ()(const Kernel::Point_2 & storage) const195 Kernel::FT operator()( const Kernel::Point_2& storage ) const {
196 return storage.y();
197 }
operator ()(const Kernel::Point_3 & storage) const198 Kernel::FT operator()( const Kernel::Point_3& storage ) const {
199 return storage.y();
200 }
201 };
202
203 ///
204 ///
205 ///
y() const206 Kernel::FT Coordinate::y() const
207 {
208 GetYVisitor visitor;
209 return boost::apply_visitor( visitor, _storage );
210 }
211
212 class GetZVisitor : public boost::static_visitor<Kernel::FT> {
213 public:
operator ()(const Coordinate::Empty &) const214 Kernel::FT operator()( const Coordinate::Empty& ) const {
215 BOOST_THROW_EXCEPTION( Exception( "trying to get an empty coordinate z value" ) );
216 return 0;
217 }
operator ()(const Kernel::Point_2 &) const218 Kernel::FT operator()( const Kernel::Point_2& ) const {
219 return 0;
220 }
operator ()(const Kernel::Point_3 & storage) const221 Kernel::FT operator()( const Kernel::Point_3& storage ) const {
222 return storage.z();
223 }
224 };
225
226 ///
227 ///
228 ///
z() const229 Kernel::FT Coordinate::z() const
230 {
231 GetZVisitor visitor;
232 return boost::apply_visitor( visitor, _storage );
233 }
234
235 //----------------------
236
237
238 class RoundVisitor : public boost::static_visitor<> {
239 public:
RoundVisitor(const long & scaleFactor)240 RoundVisitor( const long& scaleFactor ):
241 _scaleFactor( scaleFactor ) {
242
243 }
244
operator ()(Coordinate::Empty &) const245 void operator()( Coordinate::Empty& ) const {
246
247 }
operator ()(Kernel::Point_2 & storage) const248 void operator()( Kernel::Point_2& storage ) const {
249 storage = Kernel::Point_2(
250 _roundFT( storage.x() ),
251 _roundFT( storage.y() )
252 );
253 }
operator ()(Kernel::Point_3 & storage) const254 void operator()( Kernel::Point_3& storage ) const {
255 storage = Kernel::Point_3(
256 _roundFT( storage.x() ),
257 _roundFT( storage.y() ),
258 _roundFT( storage.z() )
259 );
260 }
261
262
263
264 private:
265 long _scaleFactor ;
266
267
_roundFT(const Kernel::FT & v) const268 Kernel::FT _roundFT( const Kernel::FT& v ) const {
269 #ifdef CGAL_USE_GMPXX
270 ::mpq_class q( SFCGAL::round( v.exact() * _scaleFactor ),
271 _scaleFactor) ;
272 q.canonicalize();
273 return Kernel::FT(q);
274 #else
275 return Kernel::FT( CGAL::Gmpq(
276 SFCGAL::round( v.exact() * _scaleFactor ),
277 _scaleFactor
278 ) ) ;
279 #endif
280 }
281
282 };
283
284
round(const long & scaleFactor)285 Coordinate& Coordinate::round( const long& scaleFactor )
286 {
287 RoundVisitor roundVisitor( scaleFactor ) ;
288 boost::apply_visitor( roundVisitor, _storage ) ;
289 return *this ;
290 }
291
292
293
294 //----------------------
295
296 class ToPoint2Visitor : public boost::static_visitor<Kernel::Point_2> {
297 public:
operator ()(const Coordinate::Empty &) const298 Kernel::Point_2 operator()( const Coordinate::Empty& ) const {
299 return Kernel::Point_2( CGAL::ORIGIN );
300 }
operator ()(const Kernel::Point_2 & storage) const301 Kernel::Point_2 operator()( const Kernel::Point_2& storage ) const {
302 return storage;
303 }
operator ()(const Kernel::Point_3 & storage) const304 Kernel::Point_2 operator()( const Kernel::Point_3& storage ) const {
305 return Kernel::Point_2( storage.x(), storage.y() );
306 }
307 };
308
309 ///
310 ///
311 ///
toPoint_2() const312 Kernel::Point_2 Coordinate::toPoint_2() const
313 {
314 ToPoint2Visitor visitor;
315 return boost::apply_visitor( visitor, _storage );
316 }
317
318 class ToPoint3Visitor : public boost::static_visitor<Kernel::Point_3> {
319 public:
operator ()(const Coordinate::Empty &) const320 Kernel::Point_3 operator()( const Coordinate::Empty& /*storage*/ ) const {
321 return Kernel::Point_3( CGAL::ORIGIN );
322 }
operator ()(const Kernel::Point_2 & storage) const323 Kernel::Point_3 operator()( const Kernel::Point_2& storage ) const {
324 return Kernel::Point_3( storage.x(), storage.y(), 0.0 );
325 }
operator ()(const Kernel::Point_3 & storage) const326 Kernel::Point_3 operator()( const Kernel::Point_3& storage ) const {
327 return storage;
328 }
329 };
330
331 ///
332 ///
333 ///
toPoint_3() const334 Kernel::Point_3 Coordinate::toPoint_3() const
335 {
336 ToPoint3Visitor visitor;
337 return boost::apply_visitor( visitor, _storage );
338 }
339
340 ///
341 ///
342 ///
operator <(const Coordinate & other) const343 bool Coordinate::operator < ( const Coordinate& other ) const
344 {
345 // no empty comparison
346 if ( isEmpty() || other.isEmpty() ) {
347 BOOST_THROW_EXCEPTION( Exception( "try to compare empty points using a < b " ) );
348 }
349
350 // no mixed dimension comparison
351 if ( ( is3D() && ! other.is3D() ) || ( ! is3D() && other.is3D() ) ) {
352 BOOST_THROW_EXCEPTION( Exception( "try to compare empty points with different coordinate dimension using a < b" ) );
353 }
354
355 // comparison along x
356 if ( x() < other.x() ) {
357 return true ;
358 }
359 else if ( other.x() < x() ) {
360 return false;
361 }
362
363 // comparison along y
364 if ( y() < other.y() ) {
365 return true ;
366 }
367 else if ( other.y() < y() ) {
368 return false;
369 }
370
371 // comparison along z if possible
372 if ( is3D() ) {
373 if ( z() < other.z() ) {
374 return true ;
375 }
376 else if ( other.z() < z() ) {
377 return false;
378 }
379 }
380
381 // points are equals
382 return false;
383 }
384
385 ///
386 ///
387 ///
operator ==(const Coordinate & other) const388 bool Coordinate::operator == ( const Coordinate& other ) const
389 {
390 if ( isEmpty() ) {
391 return other.isEmpty() ;
392 }
393
394 if ( is3D() || other.is3D() ) {
395 return x() == other.x() && y() == other.y() && z() == other.z() ;
396 }
397 else {
398 return x() == other.x() && y() == other.y() ;
399 }
400 }
401
402 ///
403 ///
404 ///
operator !=(const Coordinate & other) const405 bool Coordinate::operator != ( const Coordinate& other ) const
406 {
407 return ! ( *this == other );
408 }
409
410
411 }//SFCGAL
412
413