Add MPFRC++ mpreal type
[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(const 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;
18         unsigned right;
19         unsigned top;
20         unsigned bottom;
21         
22         for (unsigned i = m_start; i <= m_end; ++i)
23         {
24                 const Rect & objb = objects.bounds[i];
25                 
26                 if (i == m_start || objb.x < xmin)
27                 {
28                         xmin = objb.x;
29                         left = i;
30                 }
31                 if (i == m_start || (objb.x+objb.w) > xmax)
32                 {
33                         xmax = (objb.x+objb.w);
34                         right = i;
35                 }
36                         
37                 if (i == m_start || objb.y < ymin)
38                 {
39                         ymin = objb.y;
40                         top = i;
41                 }
42                 if (i == m_start || (objb.y+objb.h) > ymax)
43                 {
44                         ymax = (objb.y+objb.h);
45                         bottom = i;
46                 }       
47         }
48         
49         // Get actual turning point coords of the 4 edge case beziers
50         m_top = objects.beziers[objects.data_indices[top]].ToAbsolute(objects.bounds[top]).GetTop();
51         m_bottom = objects.beziers[objects.data_indices[bottom]].ToAbsolute(objects.bounds[bottom]).GetBottom();
52         m_left = objects.beziers[objects.data_indices[left]].ToAbsolute(objects.bounds[left]).GetLeft();
53         m_right = objects.beziers[objects.data_indices[right]].ToAbsolute(objects.bounds[right]).GetRight();    
54 }
55
56
57 bool Path::PointInside(const Objects & objects, const Vec2 & pt, bool debug) const
58 {
59         vector<Vec2> x_ints;
60         vector<Vec2> y_ints;
61         for (unsigned i = m_start; i <= m_end; ++i)
62         {
63                 Bezier bez(objects.beziers[objects.data_indices[i]].ToAbsolute(objects.bounds[i]));
64                 vector<Vec2> xi(bez.SolveX(pt.x));
65                 vector<Vec2> yi(bez.SolveY(pt.y));
66                 x_ints.insert(x_ints.end(), xi.begin(), xi.end());
67                 y_ints.insert(y_ints.end(), yi.begin(), yi.end());
68         }
69         //Debug("Solved for intersections");
70         unsigned bigger = 0;
71         unsigned smaller = 0;
72         for (unsigned i = 0; i < x_ints.size(); ++i)
73         {
74                 if (debug)
75                                 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));
76                 if (x_ints[i].y >= pt.y)
77                 {
78                         
79                         ++bigger;
80                 }
81         }
82         smaller = x_ints.size() - bigger;
83         if (debug)
84         {
85                 Debug("%u horizontal, %u bigger, %u smaller", x_ints.size(), bigger, smaller);
86         }
87         if (smaller % 2 == 0 || bigger % 2 == 0)
88                 return false;
89                 
90         bigger = 0;
91         smaller = 0;
92
93         for (unsigned i = 0; i < y_ints.size(); ++i)
94         {
95                 if (debug)
96                                 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));
97                 if (y_ints[i].x >= pt.x)
98                 {
99                         
100                         ++bigger;
101                 }
102         }
103         smaller = y_ints.size() - bigger;
104         if (debug)
105         {
106                 Debug("%u vertical, %u bigger, %u smaller", y_ints.size(), bigger, smaller);
107         }
108         if (smaller % 2 == 0 || bigger % 2 == 0)
109                 return false;
110                 
111                 
112         return true;
113 }
114
115 vector<Vec2> & Path::FillPoints(const Objects & objects, const View & view)
116 {
117         if (m_fill_points.size() != 0)
118                 return m_fill_points;
119                 
120         
121         for (unsigned i = m_start; i <= m_end; ++i)
122         {
123                 const Rect & objb = objects.bounds[i];
124                 // find fill points
125                 Vec2 pt;
126                 // left
127                 pt = Vec2(objb.x, objb.y+objb.h/Real(2));
128                 if (PointInside(objects, pt))
129                         m_fill_points.push_back(pt);
130                 // right
131                 pt = Vec2(objb.x+objb.w, objb.y+objb.h/Real(2));
132                 if (PointInside(objects, pt))
133                         m_fill_points.push_back(pt);
134                 // bottom
135                 pt = Vec2(objb.x+objb.w/Real(2), objb.y+objb.h);
136                 if (PointInside(objects, pt))
137                         m_fill_points.push_back(pt);
138                 // top
139                 pt = Vec2(objb.x+objb.w/Real(2), objb.y);
140                 if (PointInside(objects, pt))
141                         m_fill_points.push_back(pt);
142                         
143                 // topleft
144                 pt = Vec2(objb.x, objb.y);
145                 if (PointInside(objects, pt))
146                         m_fill_points.push_back(pt);
147                 // topright
148                 pt = Vec2(objb.x+objb.w, objb.y);
149                 if (PointInside(objects, pt))
150                         m_fill_points.push_back(pt);
151                 // bottom left
152                 pt = Vec2(objb.x, objb.y+objb.h);
153                 if (PointInside(objects, pt))
154                         m_fill_points.push_back(pt);
155                 // bottom right
156                 pt = Vec2(objb.x+objb.w, objb.y);
157                 if (PointInside(objects, pt))
158                         m_fill_points.push_back(pt);
159                         
160                 // mid
161                 pt = Vec2(objb.x+objb.w/Real(2), objb.y+objb.h/Real(2));
162                 if (PointInside(objects, pt))
163                         m_fill_points.push_back(pt);
164                 
165                 
166         }
167         
168         // 4 extrema
169         Vec2 pt = (m_top + m_bottom)/2;
170         if (PointInside(objects, pt))
171                 m_fill_points.push_back(pt);
172         pt = (m_left + m_right)/2;
173         if (PointInside(objects, pt))
174                 m_fill_points.push_back(pt);
175         pt = (m_left + m_right + m_top + m_bottom)/4;
176         if (PointInside(objects, pt))
177                 m_fill_points.push_back(pt);
178                 
179         return m_fill_points;
180 }
181
182 Rect Path::SolveBounds(const Objects & objects) const
183 {
184                 return Rect(m_left.x, m_top.y, m_right.x-m_left.x, m_bottom.y-m_top.y);
185 }
186
187 }

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