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