neoGFX
Cross-platform C++ app/game engine
Loading...
Searching...
No Matches
path.hpp
Go to the documentation of this file.
1// path.hpp
2/*
3 neogfx C++ App/Game Engine
4 Copyright (c) 2015, 2020 Leigh Johnston. All Rights Reserved.
5
6 This program is free software: you can redistribute it and / or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
18*/
19
20#pragma once
21
22#include <neogfx/neogfx.hpp>
24
25namespace neogfx
26{
27 enum class path_shape : uint32_t
28 {
30 Quads,
31 Lines,
35 };
36
37 template <typename PointType>
39 {
40 // types
41 public:
42 typedef PointType point_type;
43 typedef typename point_type::coordinate_type coordinate_type;
44 typedef typename point_type::coordinate_type coordinate_delta_type;
45 typedef typename point_type::coordinate_type dimension_type;
53 struct clip_rect_list : std::vector<mesh_type>
54 {
55 bool contains(const point_type& aPoint) const
56 {
57 for (auto const& m : *this)
58 if (m.contains(aPoint))
59 return true;
60 return false;
61 }
62 };
63 public:
64 struct missing_move_to : std::logic_error { missing_move_to() : std::logic_error("neogfx::basic_path::missing_move_to") {} };
65 private:
66 struct intersect
67 {
68 // construction
69 public:
70 intersect() : iX(), iSkip() {}
71 intersect(coordinate_type aX, bool aSkip = false) : iX(aX), iSkip(aSkip) {}
72 // operations
73 public:
74 coordinate_type x() const { return iX; }
75 bool skip() const { return iSkip; }
76 bool operator==(const intersect& aOther) const { return iX == aOther.iX; }
77 bool operator<(const intersect& aOther) const { return iX < aOther.iX; }
78 // attributes
79 private:
81 bool iSkip;
82 };
83 typedef std::vector<intersect> intersect_list;
84 // construction
85 public:
86 basic_path(path_shape aShape = path_shape::ConvexPolygon, sub_paths_size_type aPathCountHint = 0) : iShape(aShape)
87 {
88 iSubPaths.reserve(aPathCountHint);
89 }
90 basic_path(const mesh_type& aRect, path_shape aShape = path_shape::ConvexPolygon) : iShape(aShape)
91 {
92 move_to(aRect.top_left());
93 line_to(aRect.top_right());
94 line_to(aRect.bottom_right());
95 line_to(aRect.bottom_left());
96 line_to(aRect.top_left());
97 }
98 // operations
99 public:
101 {
102 return iShape;
103 }
104 void set_shape(path_shape aShape)
105 {
106 iShape = aShape;
107 }
109 {
110 return iPosition;
111 }
112 void set_position(point_type aPosition)
113 {
114 iPosition = aPosition;
115 iBoundingRect = invalid;
116 }
117 const sub_paths_type& sub_paths() const
118 {
119 return iSubPaths;
120 }
122 {
123 return iSubPaths;
124 }
126 {
127 vertices result;
128 result.reserve((aPath.size() + 1) * (iShape == path_shape::Quads ? 6 : 1));
129 if (aPath.size() >= 2)
130 {
131 if (iShape == path_shape::ConvexPolygon)
132 {
133 auto const& boundingRect = bounding_rect(false);
134 auto const& center = boundingRect.center();
135 result.push_back(xyz{ center.x + position().x, center.y + position().y });
136 }
137 for (auto vi = aPath.begin(); vi != aPath.end(); ++vi)
138 {
139 switch (iShape)
140 {
142 if (vi + 1 != aPath.end())
143 {
144 result.push_back(xyz{ vi->x + position().x, vi->y + position().y });
145 result.push_back(xyz{ (vi + 1)->x + position().x, (vi + 1)->y + position().y });
146 result.push_back(xyz{ vi->x + position().x, vi->y + position().y });
147 result.push_back(xyz{ (vi + 1)->x + position().x, (vi + 1)->y + position().y });
148 }
149 break;
151 default:
152 result.push_back(xyz{ vi->x + position().x, vi->y + position().y });
153 break;
154 }
155 }
156 if (iShape == path_shape::LineLoop && aPath[0] == aPath[aPath.size() - 1])
157 {
158 result.pop_back();
159 }
160 else if (iShape == path_shape::ConvexPolygon && aPath[0] != aPath[aPath.size() - 1])
161 {
162 result.push_back(xyz{ aPath[0].x, aPath[0].y });
163 }
164 }
165 return result;
166 }
167 void move_to(const point_type& aPoint, sub_paths_size_type aLineCountHint = 0)
168 {
169 iPointFrom = aPoint;
170 iLineCountHint = aLineCountHint;
171 }
173 {
174 move_to(point_type(aX, aY), aLineCountHint);
175 }
176 void line_to(const point_type& aPoint)
177 {
178 if (iPointFrom)
179 {
180 iSubPaths.push_back(sub_path_type{});
181 if (iLineCountHint != 0)
182 {
183 iSubPaths.back().reserve(iLineCountHint + 1);
184 iLineCountHint = 0;
185 }
186 iSubPaths.back().push_back(*iPointFrom);
187 iPointFrom = std::nullopt;
188 }
189 else
190 {
191 if (iSubPaths.empty())
192 throw missing_move_to();
193 }
194 if (iSubPaths.back().empty() || iSubPaths.back().back() != aPoint)
195 iSubPaths.back().push_back(aPoint);
196 iBoundingRect = invalid;
197 }
199 {
200 line_to(point_type{ aX, aY });
201 }
202 void add_rect(const mesh_type& aRectangle);
203 void inflate(const delta_type& aDelta)
204 {
205 auto const boundingRect = bounding_rect(false);
206 auto const center = boundingRect.center();
207 for (auto& segment : iSubPaths)
208 for (auto& point : segment)
209 {
210 if (point.x < center.x)
211 point.x -= aDelta.dx;
212 else
213 point.x += aDelta.dx;
214 if (point.y < center.y)
215 point.y -= aDelta.dy;
216 else
217 point.y += aDelta.dy;
218 }
219 iBoundingRect = invalid;
220 }
222 {
223 inflate(delta_type(aDeltaX, aDeltaY));
224 }
225 void deflate(const delta_type& aDeltas)
226 {
227 inflate(-aDeltas);
228 }
230 {
231 inflate(delta_type(-aDeltaX, -aDeltaY));
232 }
233 mesh_type bounding_rect(bool aOffsetPosition = true, size_type aPixelWidthAdjustment = size_type{}) const;
234 clip_rect_list clip_rects(const point& aOrigin) const;
235 // attributes
236 private:
237 path_shape iShape;
238 point_type iPosition;
239 std::optional<point_type> iPointFrom;
240 sub_paths_type iSubPaths;
241 sub_paths_size_type iLineCountHint;
242 mutable cache<std::tuple<bool, size_type, mesh_type>> iBoundingRect;
243 };
244}
245
246#include "path.inl"
247
248namespace neogfx
249{
250 typedef basic_path<point> path;
251 typedef std::optional<path> optional_path;
252}
coordinate_type dy
coordinate_type dx
void set_shape(path_shape aShape)
Definition path.hpp:104
vertices to_vertices(const typename sub_paths_type::value_type &aPath) const
Definition path.hpp:125
basic_rect< coordinate_type > mesh_type
Definition path.hpp:48
point_type position() const
Definition path.hpp:108
mesh_type bounding_rect(bool aOffsetPosition=true, size_type aPixelWidthAdjustment=size_type{}) const
Definition path.inl:34
clip_rect_list clip_rects(const point &aOrigin) const
Definition path.inl:82
void set_position(point_type aPosition)
Definition path.hpp:112
point_type::coordinate_type dimension_type
Definition path.hpp:45
void inflate(const delta_type &aDelta)
Definition path.hpp:203
PointType point_type
Definition path.hpp:42
void deflate(coordinate_delta_type aDeltaX, coordinate_delta_type aDeltaY)
Definition path.hpp:229
basic_line< coordinate_type > line_type
Definition path.hpp:49
const sub_paths_type & sub_paths() const
Definition path.hpp:117
path_shape shape() const
Definition path.hpp:100
void add_rect(const mesh_type &aRectangle)
Definition path.inl:23
basic_path(const mesh_type &aRect, path_shape aShape=path_shape::ConvexPolygon)
Definition path.hpp:90
basic_delta< coordinate_type > delta_type
Definition path.hpp:47
sub_paths_type::size_type sub_paths_size_type
Definition path.hpp:52
basic_path(path_shape aShape=path_shape::ConvexPolygon, sub_paths_size_type aPathCountHint=0)
Definition path.hpp:86
void deflate(const delta_type &aDeltas)
Definition path.hpp:225
basic_size< coordinate_type > size_type
Definition path.hpp:46
neolib::vecarray< sub_path_type, 1, -1 > sub_paths_type
Definition path.hpp:51
void move_to(coordinate_type aX, coordinate_type aY, sub_paths_size_type aLineCountHint=0)
Definition path.hpp:172
void move_to(const point_type &aPoint, sub_paths_size_type aLineCountHint=0)
Definition path.hpp:167
void line_to(const point_type &aPoint)
Definition path.hpp:176
neolib::vecarray< point_type, 16, -1 > sub_path_type
Definition path.hpp:50
point_type::coordinate_type coordinate_delta_type
Definition path.hpp:44
void line_to(coordinate_type aX, coordinate_type aY)
Definition path.hpp:198
void inflate(coordinate_delta_type aDeltaX, coordinate_delta_type aDeltaY)
Definition path.hpp:221
point_type::coordinate_type coordinate_type
Definition path.hpp:43
sub_paths_type & sub_paths()
Definition path.hpp:121
coordinate_type x
coordinate_type y
point_type top_left() const
point_type top_right() const
point_type bottom_left() const
point_type bottom_right() const
void reserve(size_type n)
Definition vecarray.hpp:633
reference back()
Definition vecarray.hpp:454
bool empty() const
Definition vecarray.hpp:439
void push_back(const value_type &value)
Definition vecarray.hpp:566
path_shape
Definition path.hpp:28
bool operator<(const basic_rect< CoordinateType, CoordinateSystem > &left, const basic_rect< CoordinateType, CoordinateSystem > &right)
bool operator==(const basic_rect< CoordinateType, CoordinateSystem > &left, const basic_rect< CoordinateType, CoordinateSystem > &right)
basic_point< coordinate > point
mesh_type
Definition shapes.hpp:28
vec3_list vertices
bool contains(const point_type &aPoint) const
Definition path.hpp:55