Gorgon Game Engine
Line.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include "Polygon.h"
4 
5 namespace Gorgon { namespace CGI {
6 
7  struct StrokeSettings {
9  }
10 
12 
13  };
14 
18  template<int S_ = 8, class P_= Geometry::Pointf>
19  std::vector<Geometry::PointList<P_>> LinesToPolygons(const Geometry::PointList<P_> &p, StrokeSettings settings = 1.0) {
20  if(p.GetSize() == 0) return {};
21 
22  std::vector<Geometry::PointList<P_>> points;
23  points.push_back({});
24  points.push_back({});
25 
26  // To ensure thickness is corrected for strictly inside
27  Float w = settings.width / 2/* + 1.0f / (S_ * 4)*/;
28 
29  Geometry::Line<P_> prev;
30  Geometry::Pointf prevoff;
31 
32  //first point is special
33  {
34  Geometry::Line<P_> l = p.GetLine(0);
35  auto off = (Geometry::Pointf(l.End) - Geometry::Pointf(l.Start)).Perpendicular().Normalize() * w;
36 
37  //if closed the first two points will be added last
38  if(p.Front() != p.Back()) {
39  //point for left polygon
40  points[0].Push(l.Start + off);
41 
42  //point for right polygon
43  points[1].Push(l.Start - off);
44  }
45 
46  //point for left polygon
47  points[0].Push(l.End + off);
48 
49  //point for right polygon
50  points[1].Push(l.End - off);
51 
52  prev = l;
53  prevoff = off;
54  }
55 
56 
57  for(int i=1; i<p.GetSize()-1; i++) {
58  Geometry::Line<P_> l = p.GetLine(i);
59 
60  if(l.Start == l.End)
61  continue;
62 
63  auto off = (Geometry::Pointf(l.End) - Geometry::Pointf(l.Start)).Perpendicular().Normalize() * w;
64 
65  auto prevv = (prev.End - prev.Start).Normalize();
66  auto dotp = (prevv * off);
67 
68  auto r = l.End - l.Start;
69  auto s = prev.End - prev.Start;
70 
71  if(dotp > 0) {
72  auto p = l.Start - off;
73  auto q = prev.Start - prevoff;
74 
75  auto pos = ((q - p).CrossProduct(r) / r.CrossProduct(s));
76  if(pos<0)
77  pos = 0;
78  if(pos>1)
79  pos = 1;
80  auto intersect = q + s * pos;
81 
82  points[1].Pop();
83  points[1].Push(intersect);
84  }
85  else if(dotp != 0) {
86  points[1].Push(l.Start - off);
87  }
88  points[1].Push(l.End - off);
89 
90  if(dotp < 0) {
91  auto p = l.Start + off;
92  auto q = prev.Start + prevoff;
93 
94  auto pos = ((q - p).CrossProduct(r) / r.CrossProduct(s));
95  if(pos<0)
96  pos = 0;
97  if(pos>1)
98  pos = 1;
99  auto intersect = q + s * pos;
100 
101  points[0].Pop();
102  points[0].Push(intersect);
103  }
104  else if(dotp != 0) {
105  points[0].Push(l.Start + off);
106  }
107  points[0].Push(l.End + off);
108 
109  prev = l;
110  prevoff = off;
111  }
112 
113  //if closed, keep left/right polygons separate
114  if(p.Front() == p.Back()) {
115  //add start points of first line by checking the angle with the last line
116  Geometry::Line<P_> l = p.GetLine(0);
117 
118  auto off = (Geometry::Pointf(l.End) - Geometry::Pointf(l.Start)).Perpendicular().Normalize() * w;
119 
120  auto prevv = (prev.End - prev.Start).Normalize();
121  auto dotp = (prevv * off);
122 
123  auto r = l.End - l.Start;
124  auto s = prev.End - prev.Start;
125 
126  if(dotp > 0) {
127  auto p = l.Start - off;
128  auto q = prev.Start - prevoff;
129 
130  auto pos = ((q - p).CrossProduct(r) / r.CrossProduct(s));
131  if(pos<0)
132  pos = 0;
133  if(pos>1)
134  pos = 1;
135  auto intersect = q + s * pos;
136 
137  points[1].Pop();
138  points[1].Push(intersect);
139  }
140  else if(dotp != 0) {
141  points[1].Push(l.Start - off);
142  }
143 
144  if(dotp < 0) {
145  auto p = l.Start + off;
146  auto q = prev.Start + prevoff;
147 
148  auto pos = ((q - p).CrossProduct(r) / r.CrossProduct(s));
149  if(pos<0)
150  pos = 0;
151  if(pos>1)
152  pos = 1;
153  auto intersect = q + s * pos;
154 
155  points[0].Pop();
156  points[0].Push(intersect);
157  }
158  else if(dotp != 0) {
159  points[0].Push(l.Start + off);
160  }
161 
162  points[0].Push(points[0][0]);
163  points[1].Push(points[1][0]);
164  std::reverse(points[1].begin(), points[1].end());
165  }
166  else { //if open join left/right polygons
167  for(auto it=points[1].rbegin(); it!=points[1].rend(); ++it) {
168  points[0].Push(*it);
169  }
170  points[0].Push(points[0][0]);
171  points.pop_back();
172  }
173 
174  return points;
175  }
176 
177 
181  template<int S_ = 8, class P_= Geometry::Pointf, class F_ = SolidFill<>>
183  auto points = LinesToPolygons<S_, P_>(p, settings);
184 
185  Polyfill<S_, 0, P_, F_>(target, points, stroke);
186  }
187 
191  template<int S_ = 8, class P_= Geometry::Pointf, class F_ = SolidFill<>>
193  auto points = LinesToPolygons<S_, P_>(p, settings);
194 
195  Polyfill<S_, 0, P_, F_>(target, points, stroke);
196  }
197 
201  template<int S_ = 8, class P_= Geometry::Pointf, class F_ = SolidFill<>>
202  void DrawLines(Containers::Image &target, const std::vector<Geometry::PointList<P_>> &pnts, StrokeSettings settings = 1.0, F_ stroke = SolidFill<>{Graphics::Color::Black}) {
203  std::vector<Geometry::PointList<P_>> points;
204  for(auto &p : pnts) {
205  for(auto &np : LinesToPolygons<S_, P_>(p, settings)) {
206  for(auto &p : np) {
207  std::cout<<"{"<<round(p.X*10)/10<<","<<round(p.Y*10)/10<<"}, ";
208  }
209  std::cout<<std::endl;
210  points.push_back(std::move(np));
211  }
212  }
213 
214  Polyfill<S_, 0, P_, F_>(target, points, stroke);
215  }
216 
220  template<int S_ = 8, class P_= Geometry::Pointf, class F_ = SolidFill<>>
221  void DrawLines(Graphics::Bitmap &target, const std::vector<Geometry::PointList<P_>> &pnts, StrokeSettings settings = 1.0, F_ stroke = SolidFill<>{Graphics::Color::Black}) {
222  std::vector<Geometry::PointList<P_>> points;
223  for(auto &p : pnts) {
224  for(auto &np : LinesToPolygons<S_, P_>(p, settings)) {
225  points.push_back(std::move(np));
226  }
227  }
228 
229  Polyfill<S_, 0, P_, F_>(target, points, stroke);
230  }
231 
232 
233 } }
Gorgon::Geometry::Line::End
P_ End
Ending point of the line.
Definition: Line.h:84
Gorgon::CGI::SolidFill
Fills a drawing with a solid color.
Definition: CGI.h:11
Gorgon::Geometry::PointList::Front
P_ & Front()
Accesses the first element in the list.
Definition: PointList.h:125
Gorgon::Geometry::PointList::GetLine
Line< P_ > GetLine(long index) const
Returns the line at the given index.
Definition: PointList.h:165
Gorgon::CGI::StrokeSettings::StrokeSettings
StrokeSettings(Float width=1.0f)
Definition: Line.h:8
Gorgon::CGI::DrawLines
void DrawLines(Containers::Image &target, const Geometry::PointList< P_ > &p, StrokeSettings settings=1.0, F_ stroke=SolidFill<>{Graphics::Color::Black})
Draw a point list as a list of lines.
Definition: Line.h:182
Gorgon::CGI::StrokeSettings::width
Float width
Definition: Line.h:11
Gorgon::Geometry::Line
This class represents a set of points.
Definition: Line.h:16
Gorgon::begin
std::vector< T_ >::const_iterator begin(enum_type_id< T_ >)
Definition: Enum.h:283
Gorgon::Graphics::Color::Black
constexpr RGBA Black
Definition: Color.h:653
Gorgon::Float
float Float
Represents floating point data type.
Definition: Types.h:16
Gorgon
Root namespace for Gorgon Game Engine.
Definition: Any.h:19
Gorgon::Geometry::Line::Start
P_ Start
Starting point of the line.
Definition: Line.h:81
Gorgon::Geometry::PointList::GetSize
auto GetSize() const
Returns the number of elements in the list.
Definition: PointList.h:70
Gorgon::Graphics::Bitmap
This object contains an bitmap image.
Definition: Bitmap.h:25
Gorgon::CGI::StrokeSettings
Definition: Line.h:7
Gorgon::Geometry::Pointf
basic_Point< Float > Pointf
Definition: Point.h:601
Gorgon::CGI::LinesToPolygons
std::vector< Geometry::PointList< P_ > > LinesToPolygons(const Geometry::PointList< P_ > &p, StrokeSettings settings=1.0)
Returns the polygon to draw a list of lines.
Definition: Line.h:19
Gorgon::Geometry::basic_Point
This class represents a 2D point.
Definition: Point.h:32
Gorgon::Geometry::PointList::Back
P_ & Back()
Accesses the last element in the list.
Definition: PointList.h:130
Polygon.h
Gorgon::Containers::basic_Image
This class is a container for image data.
Definition: Image.h:19
Gorgon::end
std::vector< T_ >::const_iterator end(enum_type_id< T_ >)
Definition: Enum.h:288
Gorgon::Geometry::PointList
This class represents a set of points.
Definition: PointList.h:17