Mostly features added to DebugScript
[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         m_bounds = SolveBounds(objects).Convert<PReal>();
58         #ifdef TRANSFORM_BEZIERS_TO_PATH
59         for (unsigned i = m_start; i <= m_end; ++i)
60         {
61                 //Debug("Transform %s -> %s", objects.bounds[i].Str().c_str(), bounds.Str().c_str());
62                 objects.bounds[i] = TransformRectCoordinates(m_bounds.Convert<Real>(), objects.bounds[i]);
63                 //Debug("-> %s", objects.bounds[i].Str().c_str());
64         }
65         #endif
66 }
67
68
69 bool Path::PointInside(const Objects & objects, const Vec2 & pt, bool debug) const
70 {
71         vector<Vec2> x_ints;
72         vector<Vec2> y_ints;
73         for (unsigned i = m_start; i <= m_end; ++i)
74         {
75                 Bezier bez(objects.beziers[objects.data_indices[i]].ToAbsolute(objects.bounds[i]));
76                 vector<Vec2> xi(bez.SolveX(pt.x));
77                 vector<Vec2> yi(bez.SolveY(pt.y));
78                 x_ints.insert(x_ints.end(), xi.begin(), xi.end());
79                 y_ints.insert(y_ints.end(), yi.begin(), yi.end());
80         }
81         //Debug("Solved for intersections");
82         unsigned bigger = 0;
83         unsigned smaller = 0;
84         for (unsigned i = 0; i < x_ints.size(); ++i)
85         {
86                 if (debug)
87                                 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));
88                 if (x_ints[i].y >= pt.y)
89                 {
90                         
91                         ++bigger;
92                 }
93         }
94         smaller = x_ints.size() - bigger;
95         if (debug)
96         {
97                 Debug("%u horizontal, %u bigger, %u smaller", x_ints.size(), bigger, smaller);
98         }
99         if (smaller % 2 == 0 || bigger % 2 == 0)
100                 return false;
101                 
102         bigger = 0;
103         smaller = 0;
104
105         for (unsigned i = 0; i < y_ints.size(); ++i)
106         {
107                 if (debug)
108                                 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));
109                 if (y_ints[i].x >= pt.x)
110                 {
111                         
112                         ++bigger;
113                 }
114         }
115         smaller = y_ints.size() - bigger;
116         if (debug)
117         {
118                 Debug("%u vertical, %u bigger, %u smaller", y_ints.size(), bigger, smaller);
119         }
120         if (smaller % 2 == 0 || bigger % 2 == 0)
121                 return false;
122                 
123                 
124         return true;
125 }
126
127 vector<Vec2> & Path::FillPoints(const Objects & objects, const View & view)
128 {
129         //if (m_fill_points.size() != 0)
130                 return m_fill_points;
131                 
132         
133         for (unsigned i = m_start; i <= m_end; ++i)
134         {
135                 const Rect & objb = objects.bounds[i];
136                 // find fill points
137                 Vec2 pt;
138                 // left
139                 pt = Vec2(objb.x, objb.y+objb.h/Real(2));
140                 if (PointInside(objects, pt))
141                         m_fill_points.push_back(pt);
142                 // right
143                 pt = Vec2(objb.x+objb.w, objb.y+objb.h/Real(2));
144                 if (PointInside(objects, pt))
145                         m_fill_points.push_back(pt);
146                 // bottom
147                 pt = Vec2(objb.x+objb.w/Real(2), objb.y+objb.h);
148                 if (PointInside(objects, pt))
149                         m_fill_points.push_back(pt);
150                 // top
151                 pt = Vec2(objb.x+objb.w/Real(2), objb.y);
152                 if (PointInside(objects, pt))
153                         m_fill_points.push_back(pt);
154                         
155                 // topleft
156                 pt = Vec2(objb.x, objb.y);
157                 if (PointInside(objects, pt))
158                         m_fill_points.push_back(pt);
159                 // topright
160                 pt = Vec2(objb.x+objb.w, objb.y);
161                 if (PointInside(objects, pt))
162                         m_fill_points.push_back(pt);
163                 // bottom left
164                 pt = Vec2(objb.x, objb.y+objb.h);
165                 if (PointInside(objects, pt))
166                         m_fill_points.push_back(pt);
167                 // bottom right
168                 pt = Vec2(objb.x+objb.w, objb.y);
169                 if (PointInside(objects, pt))
170                         m_fill_points.push_back(pt);
171                         
172                 // mid
173                 pt = Vec2(objb.x+objb.w/Real(2), objb.y+objb.h/Real(2));
174                 if (PointInside(objects, pt))
175                         m_fill_points.push_back(pt);
176                 
177                 
178         }
179         
180         // 4 extrema
181         Vec2 pt = (m_top + m_bottom)/2;
182         if (PointInside(objects, pt))
183                 m_fill_points.push_back(pt);
184         pt = (m_left + m_right)/2;
185         if (PointInside(objects, pt))
186                 m_fill_points.push_back(pt);
187         pt = (m_left + m_right + m_top + m_bottom)/4;
188         if (PointInside(objects, pt))
189                 m_fill_points.push_back(pt);
190                 
191         return m_fill_points;
192 }
193
194 Rect Path::SolveBounds(const Objects & objects)
195 {
196         return Rect(m_left.x, m_top.y, m_right.x-m_left.x, m_bottom.y-m_top.y);
197 }
198
199 Rect & Path::GetBounds(Objects & objects) 
200 {
201         objects.bounds[m_index] = m_bounds.Convert<Real>();
202         return objects.bounds[m_index];
203 }
204
205 }

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