OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved. | |
3 * | |
4 * Redistribution and use in source and binary forms, with or without | |
5 * modification, are permitted provided that the following conditions | |
6 * are met: | |
7 * | |
8 * 1. Redistributions of source code must retain the above | |
9 * copyright notice, this list of conditions and the following | |
10 * disclaimer. | |
11 * 2. Redistributions in binary form must reproduce the above | |
12 * copyright notice, this list of conditions and the following | |
13 * disclaimer in the documentation and/or other materials | |
14 * provided with the distribution. | |
15 * | |
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
19 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
20 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, | |
21 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
23 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
25 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | |
27 * OF THE POSSIBILITY OF SUCH DAMAGE. | |
28 */ | |
29 | |
30 #include "config.h" | |
31 #include "core/platform/graphics/FloatPolygon.h" | |
32 | |
33 #include "wtf/MathExtras.h" | |
34 | |
35 namespace WebCore { | |
36 | |
37 static inline float determinant(const FloatSize& a, const FloatSize& b) | |
38 { | |
39 return a.width() * b.height() - a.height() * b.width(); | |
40 } | |
41 | |
42 static inline bool areCollinearPoints(const FloatPoint& p0, const FloatPoint& p1
, const FloatPoint& p2) | |
43 { | |
44 return !determinant(p1 - p0, p2 - p0); | |
45 } | |
46 | |
47 static inline bool areCoincidentPoints(const FloatPoint& p0, const FloatPoint& p
1) | |
48 { | |
49 return p0.x() == p1.x() && p0.y() == p1.y(); | |
50 } | |
51 | |
52 static inline bool isPointOnLineSegment(const FloatPoint& vertex1, const FloatPo
int& vertex2, const FloatPoint& point) | |
53 { | |
54 return point.x() >= std::min(vertex1.x(), vertex2.x()) | |
55 && point.x() <= std::max(vertex1.x(), vertex2.x()) | |
56 && areCollinearPoints(vertex1, vertex2, point); | |
57 } | |
58 | |
59 static inline unsigned nextVertexIndex(unsigned vertexIndex, unsigned nVertices,
bool clockwise) | |
60 { | |
61 return ((clockwise) ? vertexIndex + 1 : vertexIndex - 1 + nVertices) % nVert
ices; | |
62 } | |
63 | |
64 static unsigned findNextEdgeVertexIndex(const FloatPolygon& polygon, unsigned ve
rtexIndex1, bool clockwise) | |
65 { | |
66 unsigned nVertices = polygon.numberOfVertices(); | |
67 unsigned vertexIndex2 = nextVertexIndex(vertexIndex1, nVertices, clockwise); | |
68 | |
69 while (vertexIndex2 && areCoincidentPoints(polygon.vertexAt(vertexIndex1), p
olygon.vertexAt(vertexIndex2))) | |
70 vertexIndex2 = nextVertexIndex(vertexIndex2, nVertices, clockwise); | |
71 | |
72 while (vertexIndex2) { | |
73 unsigned vertexIndex3 = nextVertexIndex(vertexIndex2, nVertices, clockwi
se); | |
74 if (!areCollinearPoints(polygon.vertexAt(vertexIndex1), polygon.vertexAt
(vertexIndex2), polygon.vertexAt(vertexIndex3))) | |
75 break; | |
76 vertexIndex2 = vertexIndex3; | |
77 } | |
78 | |
79 return vertexIndex2; | |
80 } | |
81 | |
82 FloatPolygon::FloatPolygon(PassOwnPtr<Vector<FloatPoint> > vertices, WindRule fi
llRule) | |
83 : m_vertices(vertices) | |
84 , m_fillRule(fillRule) | |
85 { | |
86 unsigned nVertices = numberOfVertices(); | |
87 m_edges.resize(nVertices); | |
88 m_empty = nVertices < 3; | |
89 | |
90 if (nVertices) | |
91 m_boundingBox.setLocation(vertexAt(0)); | |
92 | |
93 if (m_empty) | |
94 return; | |
95 | |
96 unsigned minVertexIndex = 0; | |
97 for (unsigned i = 1; i < nVertices; ++i) { | |
98 const FloatPoint& vertex = vertexAt(i); | |
99 if (vertex.y() < vertexAt(minVertexIndex).y() || (vertex.y() == vertexAt
(minVertexIndex).y() && vertex.x() < vertexAt(minVertexIndex).x())) | |
100 minVertexIndex = i; | |
101 } | |
102 FloatPoint nextVertex = vertexAt((minVertexIndex + 1) % nVertices); | |
103 FloatPoint prevVertex = vertexAt((minVertexIndex + nVertices - 1) % nVertice
s); | |
104 bool clockwise = determinant(vertexAt(minVertexIndex) - prevVertex, nextVert
ex - prevVertex) > 0; | |
105 | |
106 unsigned edgeIndex = 0; | |
107 unsigned vertexIndex1 = 0; | |
108 do { | |
109 m_boundingBox.extend(vertexAt(vertexIndex1)); | |
110 unsigned vertexIndex2 = findNextEdgeVertexIndex(*this, vertexIndex1, clo
ckwise); | |
111 m_edges[edgeIndex].m_polygon = this; | |
112 m_edges[edgeIndex].m_vertexIndex1 = vertexIndex1; | |
113 m_edges[edgeIndex].m_vertexIndex2 = vertexIndex2; | |
114 m_edges[edgeIndex].m_edgeIndex = edgeIndex; | |
115 ++edgeIndex; | |
116 vertexIndex1 = vertexIndex2; | |
117 } while (vertexIndex1); | |
118 | |
119 if (edgeIndex > 3) { | |
120 const FloatPolygonEdge& firstEdge = m_edges[0]; | |
121 const FloatPolygonEdge& lastEdge = m_edges[edgeIndex - 1]; | |
122 if (areCollinearPoints(lastEdge.vertex1(), lastEdge.vertex2(), firstEdge
.vertex2())) { | |
123 m_edges[0].m_vertexIndex1 = lastEdge.m_vertexIndex1; | |
124 edgeIndex--; | |
125 } | |
126 } | |
127 | |
128 m_edges.resize(edgeIndex); | |
129 m_empty = m_edges.size() < 3; | |
130 | |
131 if (m_empty) | |
132 return; | |
133 | |
134 for (unsigned i = 0; i < m_edges.size(); ++i) { | |
135 FloatPolygonEdge* edge = &m_edges[i]; | |
136 m_edgeTree.add(EdgeInterval(edge->minY(), edge->maxY(), edge)); | |
137 } | |
138 } | |
139 | |
140 bool FloatPolygon::overlappingEdges(float minY, float maxY, Vector<const FloatPo
lygonEdge*>& result) const | |
141 { | |
142 Vector<FloatPolygon::EdgeInterval> overlappingEdgeIntervals; | |
143 m_edgeTree.allOverlaps(FloatPolygon::EdgeInterval(minY, maxY, 0), overlappin
gEdgeIntervals); | |
144 unsigned overlappingEdgeIntervalsSize = overlappingEdgeIntervals.size(); | |
145 result.resize(overlappingEdgeIntervalsSize); | |
146 for (unsigned i = 0; i < overlappingEdgeIntervalsSize; ++i) { | |
147 const FloatPolygonEdge* edge = static_cast<const FloatPolygonEdge*>(over
lappingEdgeIntervals[i].data()); | |
148 ASSERT(edge); | |
149 result[i] = edge; | |
150 } | |
151 return overlappingEdgeIntervalsSize > 0; | |
152 } | |
153 | |
154 static inline float leftSide(const FloatPoint& vertex1, const FloatPoint& vertex
2, const FloatPoint& point) | |
155 { | |
156 return ((point.x() - vertex1.x()) * (vertex2.y() - vertex1.y())) - ((vertex2
.x() - vertex1.x()) * (point.y() - vertex1.y())); | |
157 } | |
158 | |
159 bool FloatPolygon::containsEvenOdd(const FloatPoint& point) const | |
160 { | |
161 unsigned crossingCount = 0; | |
162 for (unsigned i = 0; i < numberOfEdges(); ++i) { | |
163 const FloatPoint& vertex1 = edgeAt(i).vertex1(); | |
164 const FloatPoint& vertex2 = edgeAt(i).vertex2(); | |
165 if (isPointOnLineSegment(vertex1, vertex2, point)) | |
166 return true; | |
167 if ((vertex1.y() <= point.y() && vertex2.y() > point.y()) || (vertex1.y(
) > point.y() && vertex2.y() <= point.y())) { | |
168 float vt = (point.y() - vertex1.y()) / (vertex2.y() - vertex1.y()); | |
169 if (point.x() < vertex1.x() + vt * (vertex2.x() - vertex1.x())) | |
170 ++crossingCount; | |
171 } | |
172 } | |
173 return crossingCount & 1; | |
174 } | |
175 | |
176 bool FloatPolygon::containsNonZero(const FloatPoint& point) const | |
177 { | |
178 int windingNumber = 0; | |
179 for (unsigned i = 0; i < numberOfEdges(); ++i) { | |
180 const FloatPoint& vertex1 = edgeAt(i).vertex1(); | |
181 const FloatPoint& vertex2 = edgeAt(i).vertex2(); | |
182 if (isPointOnLineSegment(vertex1, vertex2, point)) | |
183 return true; | |
184 if (vertex2.y() < point.y()) { | |
185 if ((vertex1.y() > point.y()) && (leftSide(vertex1, vertex2, point)
> 0)) | |
186 ++windingNumber; | |
187 } else if (vertex2.y() > point.y()) { | |
188 if ((vertex1.y() <= point.y()) && (leftSide(vertex1, vertex2, point)
< 0)) | |
189 --windingNumber; | |
190 } | |
191 } | |
192 return windingNumber; | |
193 } | |
194 | |
195 bool FloatPolygon::contains(const FloatPoint& point) const | |
196 { | |
197 if (!m_boundingBox.contains(point)) | |
198 return false; | |
199 return (fillRule() == RULE_NONZERO) ? containsNonZero(point) : containsEvenO
dd(point); | |
200 } | |
201 | |
202 bool VertexPair::overlapsRect(const FloatRect& rect) const | |
203 { | |
204 bool boundsOverlap = (minX() < rect.maxX()) && (maxX() > rect.x()) && (minY(
) < rect.maxY()) && (maxY() > rect.y()); | |
205 if (!boundsOverlap) | |
206 return false; | |
207 | |
208 float leftSideValues[4] = { | |
209 leftSide(vertex1(), vertex2(), rect.minXMinYCorner()), | |
210 leftSide(vertex1(), vertex2(), rect.maxXMinYCorner()), | |
211 leftSide(vertex1(), vertex2(), rect.minXMaxYCorner()), | |
212 leftSide(vertex1(), vertex2(), rect.maxXMaxYCorner()) | |
213 }; | |
214 | |
215 int currentLeftSideSign = 0; | |
216 for (unsigned i = 0; i < 4; ++i) { | |
217 if (!leftSideValues[i]) | |
218 continue; | |
219 int leftSideSign = leftSideValues[i] > 0 ? 1 : -1; | |
220 if (!currentLeftSideSign) | |
221 currentLeftSideSign = leftSideSign; | |
222 else if (currentLeftSideSign != leftSideSign) | |
223 return true; | |
224 } | |
225 | |
226 return false; | |
227 } | |
228 | |
229 bool VertexPair::intersection(const VertexPair& other, FloatPoint& point) const | |
230 { | |
231 // See: http://paulbourke.net/geometry/pointlineplane/, "Intersection point
of two lines in 2 dimensions" | |
232 | |
233 const FloatSize& thisDelta = vertex2() - vertex1(); | |
234 const FloatSize& otherDelta = other.vertex2() - other.vertex1(); | |
235 float denominator = determinant(thisDelta, otherDelta); | |
236 if (!denominator) | |
237 return false; | |
238 | |
239 // The two line segments: "this" vertex1,vertex2 and "other" vertex1,vertex2
, have been defined | |
240 // in parametric form. Each point on the line segment is: vertex1 + u * (ver
tex2 - vertex1), | |
241 // when 0 <= u <= 1. We're computing the values of u for each line at their
intersection point. | |
242 | |
243 const FloatSize& vertex1Delta = vertex1() - other.vertex1(); | |
244 float uThisLine = determinant(otherDelta, vertex1Delta) / denominator; | |
245 float uOtherLine = determinant(thisDelta, vertex1Delta) / denominator; | |
246 | |
247 if (uThisLine < 0 || uOtherLine < 0 || uThisLine > 1 || uOtherLine > 1) | |
248 return false; | |
249 | |
250 point = vertex1() + uThisLine * thisDelta; | |
251 return true; | |
252 } | |
253 | |
254 } // namespace WebCore | |
OLD | NEW |