Use Gmprat for Path bounds with TRANSFORM_BEZIERS_TO_PATH
[ipdf/code.git] / src / path.cpp
1 #include "ipdf.h"
2 #include "path.h"
3 using namespace std;
4
5 namespace IPDF
6 {
7
8 Path::Path(Objects & objects, unsigned start, unsigned end, const Colour & fill, const Colour & stroke)
9         : m_start(start), m_end(end), m_fill(fill), m_stroke(stroke)
10 {
11         Real xmin = 0; Real ymin = 0; 
12         Real xmax = 0; Real ymax = 0;
13         
14         // Find the bounds coordinates
15         //  and identify the top left and bottom right objects
16         
17         unsigned left = m_start;
18         unsigned right = m_start;
19         unsigned top = m_start;
20         unsigned bottom = m_start;
21         
22         for (unsigned i = m_start; i <= m_end; ++i)
23         {
24                 if (i >= objects.bounds.size())
25                         break;
26                 const Rect & objb = objects.bounds[i];
27                 
28                 if (i == m_start || objb.x < xmin)
29                 {
30                         xmin = objb.x;
31                         left = i;
32                 }
33                 if (i == m_start || (objb.x+objb.w) > xmax)
34                 {
35                         xmax = (objb.x+objb.w);
36                         right = i;
37                 }
38                         
39                 if (i == m_start || objb.y < ymin)
40                 {
41                         ymin = objb.y;
42                         top = i;
43                 }
44                 if (i == m_start || (objb.y+objb.h) > ymax)
45                 {
46                         ymax = (objb.y+objb.h);
47                         bottom = i;
48                 }       
49         }
50         
51         // Get actual turning point coords of the 4 edge case beziers
52         m_top = objects.beziers[objects.data_indices[top]].ToAbsolute(objects.bounds[top]).GetTop();
53         m_bottom = objects.beziers[objects.data_indices[bottom]].ToAbsolute(objects.bounds[bottom]).GetBottom();
54         m_left = objects.beziers[objects.data_indices[left]].ToAbsolute(objects.bounds[left]).GetLeft();
55         m_right = objects.beziers[objects.data_indices[right]].ToAbsolute(objects.bounds[right]).GetRight();    
56         
57         #ifdef TRANSFORM_BEZIERS_TO_PATH
58         x = m_left.x;
59         y = m_top.y;
60         w = m_right.x - m_left.x;
61         h = m_bottom.y - m_top.y;
62         
63         Rect bounds = SolveBounds(objects);
64         for (unsigned i = m_start; i <= m_end; ++i)
65         {
66                 //Debug("Transform %s -> %s", objects.bounds[i].Str().c_str(), bounds.Str().c_str());
67                 objects.bounds[i] = TransformRectCoordinates(bounds, objects.bounds[i]);
68                 //Debug("-> %s", objects.bounds[i].Str().c_str());
69         }
70         #endif
71 }
72
73
74 bool Path::PointInside(const Objects & objects, const Vec2 & pt, bool debug) const
75 {
76         vector<Vec2> x_ints;
77         vector<Vec2> y_ints;
78         for (unsigned i = m_start; i <= m_end; ++i)
79         {
80                 Bezier bez(objects.beziers[objects.data_indices[i]].ToAbsolute(objects.bounds[i]));
81                 vector<Vec2> xi(bez.SolveX(pt.x));
82                 vector<Vec2> yi(bez.SolveY(pt.y));
83                 x_ints.insert(x_ints.end(), xi.begin(), xi.end());
84                 y_ints.insert(y_ints.end(), yi.begin(), yi.end());
85         }
86         //Debug("Solved for intersections");
87         unsigned bigger = 0;
88         unsigned smaller = 0;
89         for (unsigned i = 0; i < x_ints.size(); ++i)
90         {
91                 if (debug)
92                                 Debug("X Intersection %u at %f,%f vs %f,%f", i,Double(x_ints[i].x), Double(x_ints[i].y), Double(pt.x), Double(pt.y));
93                 if (x_ints[i].y >= pt.y)
94                 {
95                         
96                         ++bigger;
97                 }
98         }
99         smaller = x_ints.size() - bigger;
100         if (debug)
101         {
102                 Debug("%u horizontal, %u bigger, %u smaller", x_ints.size(), bigger, smaller);
103         }
104         if (smaller % 2 == 0 || bigger % 2 == 0)
105                 return false;
106                 
107         bigger = 0;
108         smaller = 0;
109
110         for (unsigned i = 0; i < y_ints.size(); ++i)
111         {
112                 if (debug)
113                                 Debug("Y Intersection %u at %f,%f vs %f,%f", i,Double(y_ints[i].x), Double(y_ints[i].y), Double(pt.x), Double(pt.y));
114                 if (y_ints[i].x >= pt.x)
115                 {
116                         
117                         ++bigger;
118                 }
119         }
120         smaller = y_ints.size() - bigger;
121         if (debug)
122         {
123                 Debug("%u vertical, %u bigger, %u smaller", y_ints.size(), bigger, smaller);
124         }
125         if (smaller % 2 == 0 || bigger % 2 == 0)
126                 return false;
127                 
128                 
129         return true;
130 }
131
132 vector<Vec2> & Path::FillPoints(const Objects & objects, const View & view)
133 {
134         if (m_fill_points.size() != 0)
135                 return m_fill_points;
136                 
137         
138         for (unsigned i = m_start; i <= m_end; ++i)
139         {
140                 const Rect & objb = objects.bounds[i];
141                 // find fill points
142                 Vec2 pt;
143                 // left
144                 pt = Vec2(objb.x, objb.y+objb.h/Real(2));
145                 if (PointInside(objects, pt))
146                         m_fill_points.push_back(pt);
147                 // right
148                 pt = Vec2(objb.x+objb.w, objb.y+objb.h/Real(2));
149                 if (PointInside(objects, pt))
150                         m_fill_points.push_back(pt);
151                 // bottom
152                 pt = Vec2(objb.x+objb.w/Real(2), objb.y+objb.h);
153                 if (PointInside(objects, pt))
154                         m_fill_points.push_back(pt);
155                 // top
156                 pt = Vec2(objb.x+objb.w/Real(2), objb.y);
157                 if (PointInside(objects, pt))
158                         m_fill_points.push_back(pt);
159                         
160                 // topleft
161                 pt = Vec2(objb.x, objb.y);
162                 if (PointInside(objects, pt))
163                         m_fill_points.push_back(pt);
164                 // topright
165                 pt = Vec2(objb.x+objb.w, objb.y);
166                 if (PointInside(objects, pt))
167                         m_fill_points.push_back(pt);
168                 // bottom left
169                 pt = Vec2(objb.x, objb.y+objb.h);
170                 if (PointInside(objects, pt))
171                         m_fill_points.push_back(pt);
172                 // bottom right
173                 pt = Vec2(objb.x+objb.w, objb.y);
174                 if (PointInside(objects, pt))
175                         m_fill_points.push_back(pt);
176                         
177                 // mid
178                 pt = Vec2(objb.x+objb.w/Real(2), objb.y+objb.h/Real(2));
179                 if (PointInside(objects, pt))
180                         m_fill_points.push_back(pt);
181                 
182                 
183         }
184         
185         // 4 extrema
186         Vec2 pt = (m_top + m_bottom)/2;
187         if (PointInside(objects, pt))
188                 m_fill_points.push_back(pt);
189         pt = (m_left + m_right)/2;
190         if (PointInside(objects, pt))
191                 m_fill_points.push_back(pt);
192         pt = (m_left + m_right + m_top + m_bottom)/4;
193         if (PointInside(objects, pt))
194                 m_fill_points.push_back(pt);
195                 
196         return m_fill_points;
197 }
198
199 Rect Path::SolveBounds(const Objects & objects)
200 {
201         #ifdef TRANSFORM_BEZIERS_TO_PATH
202                 return Rect(Real(x.ToDouble()), Real(y.ToDouble()), Real(w.ToDouble()), Real(h.ToDouble()));
203         #else
204                 return Rect(m_left.x, m_top.y, m_right.x-m_left.x, m_bottom.y-m_top.y);
205         #endif
206 }
207
208 Rect & Path::GetBounds(Objects & objects) 
209 {
210         #ifdef TRANSFORM_BEZIERS_TO_PATH
211                 objects.bounds[m_index] = Rect(Real(x.ToDouble()), Real(y.ToDouble()), Real(w.ToDouble()), Real(h.ToDouble()));
212         #endif
213         return objects.bounds[m_index];
214 }
215
216 }

UCC git Repository :: git.ucc.asn.au