1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2 
3 // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
4 // Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
5 // Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
6 // Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
7 
8 // This file was modified by Oracle on 2014-2020.
9 // Modifications copyright (c) 2014-2020, Oracle and/or its affiliates.
10 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
11 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
12 
13 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
14 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
15 
16 // Use, modification and distribution is subject to the Boost Software License,
17 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
18 // http://www.boost.org/LICENSE_1_0.txt)
19 
20 #ifndef BOOST_GEOMETRY_GEOMETRIES_POINT_HPP
21 #define BOOST_GEOMETRY_GEOMETRIES_POINT_HPP
22 
23 #include <cstddef>
24 #include <type_traits>
25 
26 #include <boost/static_assert.hpp>
27 
28 #include <boost/geometry/core/access.hpp>
29 #include <boost/geometry/core/assert.hpp>
30 #include <boost/geometry/core/coordinate_type.hpp>
31 #include <boost/geometry/core/coordinate_system.hpp>
32 #include <boost/geometry/core/coordinate_dimension.hpp>
33 #include <boost/geometry/core/make.hpp>
34 #include <boost/geometry/core/tag.hpp>
35 #include <boost/geometry/core/tags.hpp>
36 
37 #if defined(BOOST_GEOMETRY_ENABLE_ACCESS_DEBUGGING)
38 #include <algorithm>
39 #include <boost/geometry/core/assert.hpp>
40 #endif
41 
42 namespace boost { namespace geometry
43 {
44 
45 // Silence warning C4127: conditional expression is constant
46 #if defined(_MSC_VER)
47 #pragma warning(push)
48 #pragma warning(disable : 4127)
49 #endif
50 
51 namespace detail
52 {
53 
54 template <typename Dummy, std::size_t N, std::size_t DimensionCount>
55 struct is_coordinates_number_leq
56 {
57     static const bool value = (N <= DimensionCount);
58 };
59 
60 template <typename Dummy, std::size_t N, std::size_t DimensionCount>
61 struct is_coordinates_number_eq
62 {
63     static const bool value = (N == DimensionCount);
64 };
65 
66 } // namespace detail
67 
68 
69 namespace model
70 {
71 
72 /*!
73 \brief Basic point class, having coordinates defined in a neutral way
74 \details Defines a neutral point class, fulfilling the Point Concept.
75     Library users can use this point class, or use their own point classes.
76     This point class is used in most of the samples and tests of Boost.Geometry
77     This point class is used occasionally within the library, where a temporary
78     point class is necessary.
79 \ingroup geometries
80 \tparam CoordinateType \tparam_numeric
81 \tparam DimensionCount number of coordinates, usually 2 or 3
82 \tparam CoordinateSystem coordinate system, for example cs::cartesian
83 
84 \qbk{[include reference/geometries/point.qbk]}
85 \qbk{before.synopsis, [heading Model of]}
86 \qbk{before.synopsis, [link geometry.reference.concepts.concept_point Point Concept]}
87 
88 
89 */
90 template
91 <
92     typename CoordinateType,
93     std::size_t DimensionCount,
94     typename CoordinateSystem
95 >
96 class point
97 {
98     BOOST_STATIC_ASSERT(DimensionCount > 0);
99 
100     // The following enum is used to fully instantiate the
101     // CoordinateSystem class and check the correctness of the units
102     // passed for non-Cartesian coordinate systems.
103     enum { cs_check = sizeof(CoordinateSystem) };
104 
105 public:
106 
107     // TODO: constexpr requires LiteralType and until C++20
108     // it has to have trivial destructor which makes access
109     // debugging impossible with constexpr.
110 
111 #if !defined(BOOST_GEOMETRY_ENABLE_ACCESS_DEBUGGING)
112     /// \constructor_default_no_init
point()113     constexpr point()
114 // Workaround for VS2015
115 #if defined(_MSC_VER) && (_MSC_VER < 1910)
116         : m_values{} {}
117 #else
118         = default;
119 #endif
120 #else // defined(BOOST_GEOMETRY_ENABLE_ACCESS_DEBUGGING)
121     point()
122     {
123         m_created = 1;
124         std::fill_n(m_values_initialized, DimensionCount, 0);
125     }
126     ~point()
127     {
128         m_created = 0;
129         std::fill_n(m_values_initialized, DimensionCount, 0);
130     }
131 #endif
132 
133     /// @brief Constructor to set one value
134     template
135     <
136         typename C = CoordinateType,
137         std::enable_if_t<geometry::detail::is_coordinates_number_leq<C, 1, DimensionCount>::value, int> = 0
138     >
139 #if ! defined(BOOST_GEOMETRY_ENABLE_ACCESS_DEBUGGING)
140     constexpr
141 #endif
point(CoordinateType const & v0)142     explicit point(CoordinateType const& v0)
143         : m_values{v0}
144     {
145 #if defined(BOOST_GEOMETRY_ENABLE_ACCESS_DEBUGGING)
146         m_created = 1;
147         std::fill_n(m_values_initialized, DimensionCount, 1);
148 #endif
149     }
150 
151     /// @brief Constructor to set two values
152     template
153     <
154         typename C = CoordinateType,
155         std::enable_if_t<geometry::detail::is_coordinates_number_leq<C, 2, DimensionCount>::value, int> = 0
156     >
157 #if ! defined(BOOST_GEOMETRY_ENABLE_ACCESS_DEBUGGING)
158     constexpr
159 #endif
point(CoordinateType const & v0,CoordinateType const & v1)160     point(CoordinateType const& v0, CoordinateType const& v1)
161         : m_values{ v0, v1 }
162     {
163 #if defined(BOOST_GEOMETRY_ENABLE_ACCESS_DEBUGGING)
164         m_created = 1;
165         std::fill_n(m_values_initialized, DimensionCount, 1);
166 #endif
167     }
168 
169     /// @brief Constructor to set three values
170     template
171     <
172         typename C = CoordinateType,
173         std::enable_if_t<geometry::detail::is_coordinates_number_leq<C, 3, DimensionCount>::value, int> = 0
174     >
175 #if ! defined(BOOST_GEOMETRY_ENABLE_ACCESS_DEBUGGING)
176     constexpr
177 #endif
point(CoordinateType const & v0,CoordinateType const & v1,CoordinateType const & v2)178     point(CoordinateType const& v0, CoordinateType const& v1, CoordinateType const& v2)
179         : m_values{ v0, v1, v2 }
180     {
181 #if defined(BOOST_GEOMETRY_ENABLE_ACCESS_DEBUGGING)
182         m_created = 1;
183         std::fill_n(m_values_initialized, DimensionCount, 1);
184 #endif
185     }
186 
187     /// @brief Get a coordinate
188     /// @tparam K coordinate to get
189     /// @return the coordinate
190     template <std::size_t K>
191 #if ! defined(BOOST_GEOMETRY_ENABLE_ACCESS_DEBUGGING)
192     constexpr
193 #endif
get() const194     CoordinateType const& get() const
195     {
196 #if defined(BOOST_GEOMETRY_ENABLE_ACCESS_DEBUGGING)
197         BOOST_GEOMETRY_ASSERT(m_created == 1);
198         BOOST_GEOMETRY_ASSERT(m_values_initialized[K] == 1);
199 #endif
200         BOOST_STATIC_ASSERT(K < DimensionCount);
201         return m_values[K];
202     }
203 
204     /// @brief Set a coordinate
205     /// @tparam K coordinate to set
206     /// @param value value to set
207     template <std::size_t K>
set(CoordinateType const & value)208     void set(CoordinateType const& value)
209     {
210 #if defined(BOOST_GEOMETRY_ENABLE_ACCESS_DEBUGGING)
211         BOOST_GEOMETRY_ASSERT(m_created == 1);
212         m_values_initialized[K] = 1;
213 #endif
214         BOOST_STATIC_ASSERT(K < DimensionCount);
215         m_values[K] = value;
216     }
217 
218 private:
219 
220     CoordinateType m_values[DimensionCount];
221 
222 #if defined(BOOST_GEOMETRY_ENABLE_ACCESS_DEBUGGING)
223     int m_created;
224     int m_values_initialized[DimensionCount];
225 #endif
226 };
227 
228 
229 } // namespace model
230 
231 // Adapt the point to the concept
232 #ifndef DOXYGEN_NO_TRAITS_SPECIALIZATIONS
233 namespace traits
234 {
235 template
236 <
237     typename CoordinateType,
238     std::size_t DimensionCount,
239     typename CoordinateSystem
240 >
241 struct tag<model::point<CoordinateType, DimensionCount, CoordinateSystem> >
242 {
243     typedef point_tag type;
244 };
245 
246 template
247 <
248     typename CoordinateType,
249     std::size_t DimensionCount,
250     typename CoordinateSystem
251 >
252 struct coordinate_type<model::point<CoordinateType, DimensionCount, CoordinateSystem> >
253 {
254     typedef CoordinateType type;
255 };
256 
257 template
258 <
259     typename CoordinateType,
260     std::size_t DimensionCount,
261     typename CoordinateSystem
262 >
263 struct coordinate_system<model::point<CoordinateType, DimensionCount, CoordinateSystem> >
264 {
265     typedef CoordinateSystem type;
266 };
267 
268 template
269 <
270     typename CoordinateType,
271     std::size_t DimensionCount,
272     typename CoordinateSystem
273 >
274 struct dimension<model::point<CoordinateType, DimensionCount, CoordinateSystem> >
275     : std::integral_constant<std::size_t, DimensionCount>
276 {};
277 
278 template
279 <
280     typename CoordinateType,
281     std::size_t DimensionCount,
282     typename CoordinateSystem,
283     std::size_t Dimension
284 >
285 struct access<model::point<CoordinateType, DimensionCount, CoordinateSystem>, Dimension>
286 {
getboost::geometry::traits::access287     static constexpr CoordinateType get(
288         model::point<CoordinateType, DimensionCount, CoordinateSystem> const& p)
289     {
290         return p.template get<Dimension>();
291     }
292 
setboost::geometry::traits::access293     static void set(
294         model::point<CoordinateType, DimensionCount, CoordinateSystem>& p,
295         CoordinateType const& value)
296     {
297         p.template set<Dimension>(value);
298     }
299 };
300 
301 template
302 <
303     typename CoordinateType,
304     std::size_t DimensionCount,
305     typename CoordinateSystem
306 >
307 struct make<model::point<CoordinateType, DimensionCount, CoordinateSystem> >
308 {
309     typedef model::point<CoordinateType, DimensionCount, CoordinateSystem> point_type;
310 
311     static const bool is_specialized = true;
312 
313     template
314     <
315         typename C = CoordinateType,
316         std::enable_if_t<geometry::detail::is_coordinates_number_eq<C, 1, DimensionCount>::value, int> = 0
317     >
applyboost::geometry::traits::make318     static constexpr point_type apply(CoordinateType const& v0)
319     {
320         return point_type(v0);
321     }
322 
323     template
324     <
325         typename C = CoordinateType,
326         std::enable_if_t<geometry::detail::is_coordinates_number_eq<C, 2, DimensionCount>::value, int> = 0
327     >
applyboost::geometry::traits::make328     static constexpr point_type apply(CoordinateType const& v0,
329                                       CoordinateType const& v1)
330     {
331         return point_type(v0, v1);
332     }
333 
334     template
335     <
336         typename C = CoordinateType,
337         std::enable_if_t<geometry::detail::is_coordinates_number_eq<C, 3, DimensionCount>::value, int> = 0
338     >
applyboost::geometry::traits::make339     static constexpr point_type apply(CoordinateType const& v0,
340                                       CoordinateType const& v1,
341                                       CoordinateType const& v2)
342     {
343         return point_type(v0, v1, v2);
344     }
345 };
346 
347 
348 } // namespace traits
349 #endif // DOXYGEN_NO_TRAITS_SPECIALIZATIONS
350 
351 #if defined(_MSC_VER)
352 #pragma warning(pop)
353 #endif
354 
355 }} // namespace boost::geometry
356 
357 #endif // BOOST_GEOMETRY_GEOMETRIES_POINT_HPP
358