|  | /* | 
|  | * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved. | 
|  | * | 
|  | * Redistribution and use in source and binary forms, with or without | 
|  | * modification, are permitted provided that the following conditions | 
|  | * are met: | 
|  | * | 
|  | * 1. Redistributions of source code must retain the above | 
|  | *    copyright notice, this list of conditions and the following | 
|  | *    disclaimer. | 
|  | * 2. Redistributions in binary form must reproduce the above | 
|  | *    copyright notice, this list of conditions and the following | 
|  | *    disclaimer in the documentation and/or other materials | 
|  | *    provided with the distribution. | 
|  | * | 
|  | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 
|  | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 
|  | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | 
|  | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | 
|  | * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, | 
|  | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | 
|  | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | 
|  | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 
|  | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | 
|  | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 
|  | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | 
|  | * OF THE POSSIBILITY OF SUCH DAMAGE. | 
|  | */ | 
|  |  | 
|  | #include "platform/geometry/FloatPolygon.h" | 
|  | #include "platform/geometry/FloatShapeHelpers.h" | 
|  |  | 
|  | #include <memory> | 
|  | #include "platform/wtf/MathExtras.h" | 
|  |  | 
|  | namespace blink { | 
|  |  | 
|  | static inline bool AreCollinearPoints(const FloatPoint& p0, | 
|  | const FloatPoint& p1, | 
|  | const FloatPoint& p2) { | 
|  | return !Determinant(p1 - p0, p2 - p0); | 
|  | } | 
|  |  | 
|  | static inline bool AreCoincidentPoints(const FloatPoint& p0, | 
|  | const FloatPoint& p1) { | 
|  | return p0.X() == p1.X() && p0.Y() == p1.Y(); | 
|  | } | 
|  |  | 
|  | static inline bool IsPointOnLineSegment(const FloatPoint& vertex1, | 
|  | const FloatPoint& vertex2, | 
|  | const FloatPoint& point) { | 
|  | return point.X() >= std::min(vertex1.X(), vertex2.X()) && | 
|  | point.X() <= std::max(vertex1.X(), vertex2.X()) && | 
|  | AreCollinearPoints(vertex1, vertex2, point); | 
|  | } | 
|  |  | 
|  | static inline unsigned NextVertexIndex(unsigned vertex_index, | 
|  | unsigned n_vertices, | 
|  | bool clockwise) { | 
|  | return ((clockwise) ? vertex_index + 1 : vertex_index - 1 + n_vertices) % | 
|  | n_vertices; | 
|  | } | 
|  |  | 
|  | static unsigned FindNextEdgeVertexIndex(const FloatPolygon& polygon, | 
|  | unsigned vertex_index1, | 
|  | bool clockwise) { | 
|  | unsigned n_vertices = polygon.NumberOfVertices(); | 
|  | unsigned vertex_index2 = | 
|  | NextVertexIndex(vertex_index1, n_vertices, clockwise); | 
|  |  | 
|  | while (vertex_index2 && AreCoincidentPoints(polygon.VertexAt(vertex_index1), | 
|  | polygon.VertexAt(vertex_index2))) | 
|  | vertex_index2 = NextVertexIndex(vertex_index2, n_vertices, clockwise); | 
|  |  | 
|  | while (vertex_index2) { | 
|  | unsigned vertex_index3 = | 
|  | NextVertexIndex(vertex_index2, n_vertices, clockwise); | 
|  | if (!AreCollinearPoints(polygon.VertexAt(vertex_index1), | 
|  | polygon.VertexAt(vertex_index2), | 
|  | polygon.VertexAt(vertex_index3))) | 
|  | break; | 
|  | vertex_index2 = vertex_index3; | 
|  | } | 
|  |  | 
|  | return vertex_index2; | 
|  | } | 
|  |  | 
|  | FloatPolygon::FloatPolygon(std::unique_ptr<Vector<FloatPoint>> vertices, | 
|  | WindRule fill_rule) | 
|  | : vertices_(std::move(vertices)), fill_rule_(fill_rule) { | 
|  | unsigned n_vertices = NumberOfVertices(); | 
|  | edges_.resize(n_vertices); | 
|  | empty_ = n_vertices < 3; | 
|  |  | 
|  | if (n_vertices) | 
|  | bounding_box_.SetLocation(VertexAt(0)); | 
|  |  | 
|  | if (empty_) | 
|  | return; | 
|  |  | 
|  | unsigned min_vertex_index = 0; | 
|  | for (unsigned i = 1; i < n_vertices; ++i) { | 
|  | const FloatPoint& vertex = VertexAt(i); | 
|  | if (vertex.Y() < VertexAt(min_vertex_index).Y() || | 
|  | (vertex.Y() == VertexAt(min_vertex_index).Y() && | 
|  | vertex.X() < VertexAt(min_vertex_index).X())) | 
|  | min_vertex_index = i; | 
|  | } | 
|  | FloatPoint next_vertex = VertexAt((min_vertex_index + 1) % n_vertices); | 
|  | FloatPoint prev_vertex = | 
|  | VertexAt((min_vertex_index + n_vertices - 1) % n_vertices); | 
|  | bool clockwise = Determinant(VertexAt(min_vertex_index) - prev_vertex, | 
|  | next_vertex - prev_vertex) > 0; | 
|  |  | 
|  | unsigned edge_index = 0; | 
|  | unsigned vertex_index1 = 0; | 
|  | do { | 
|  | bounding_box_.Extend(VertexAt(vertex_index1)); | 
|  | unsigned vertex_index2 = | 
|  | FindNextEdgeVertexIndex(*this, vertex_index1, clockwise); | 
|  | edges_[edge_index].polygon_ = this; | 
|  | edges_[edge_index].vertex_index1_ = vertex_index1; | 
|  | edges_[edge_index].vertex_index2_ = vertex_index2; | 
|  | edges_[edge_index].edge_index_ = edge_index; | 
|  | ++edge_index; | 
|  | vertex_index1 = vertex_index2; | 
|  | } while (vertex_index1); | 
|  |  | 
|  | if (edge_index > 3) { | 
|  | const FloatPolygonEdge& first_edge = edges_[0]; | 
|  | const FloatPolygonEdge& last_edge = edges_[edge_index - 1]; | 
|  | if (AreCollinearPoints(last_edge.Vertex1(), last_edge.Vertex2(), | 
|  | first_edge.Vertex2())) { | 
|  | edges_[0].vertex_index1_ = last_edge.vertex_index1_; | 
|  | edge_index--; | 
|  | } | 
|  | } | 
|  |  | 
|  | edges_.resize(edge_index); | 
|  | empty_ = edges_.size() < 3; | 
|  |  | 
|  | if (empty_) | 
|  | return; | 
|  |  | 
|  | for (unsigned i = 0; i < edges_.size(); ++i) { | 
|  | FloatPolygonEdge* edge = &edges_[i]; | 
|  | edge_tree_.Add(EdgeInterval(edge->MinY(), edge->MaxY(), edge)); | 
|  | } | 
|  | } | 
|  |  | 
|  | bool FloatPolygon::OverlappingEdges( | 
|  | float min_y, | 
|  | float max_y, | 
|  | Vector<const FloatPolygonEdge*>& result) const { | 
|  | Vector<FloatPolygon::EdgeInterval> overlapping_edge_intervals; | 
|  | edge_tree_.AllOverlaps(FloatPolygon::EdgeInterval(min_y, max_y, 0), | 
|  | overlapping_edge_intervals); | 
|  | unsigned overlapping_edge_intervals_size = overlapping_edge_intervals.size(); | 
|  | result.resize(overlapping_edge_intervals_size); | 
|  | for (unsigned i = 0; i < overlapping_edge_intervals_size; ++i) { | 
|  | const FloatPolygonEdge* edge = static_cast<const FloatPolygonEdge*>( | 
|  | overlapping_edge_intervals[i].Data()); | 
|  | DCHECK(edge); | 
|  | result[i] = edge; | 
|  | } | 
|  | return overlapping_edge_intervals_size > 0; | 
|  | } | 
|  |  | 
|  | static inline float LeftSide(const FloatPoint& vertex1, | 
|  | const FloatPoint& vertex2, | 
|  | const FloatPoint& point) { | 
|  | return ((point.X() - vertex1.X()) * (vertex2.Y() - vertex1.Y())) - | 
|  | ((vertex2.X() - vertex1.X()) * (point.Y() - vertex1.Y())); | 
|  | } | 
|  |  | 
|  | bool FloatPolygon::ContainsEvenOdd(const FloatPoint& point) const { | 
|  | unsigned crossing_count = 0; | 
|  | for (unsigned i = 0; i < NumberOfEdges(); ++i) { | 
|  | const FloatPoint& vertex1 = EdgeAt(i).Vertex1(); | 
|  | const FloatPoint& vertex2 = EdgeAt(i).Vertex2(); | 
|  | if (IsPointOnLineSegment(vertex1, vertex2, point)) | 
|  | return true; | 
|  | if ((vertex1.Y() <= point.Y() && vertex2.Y() > point.Y()) || | 
|  | (vertex1.Y() > point.Y() && vertex2.Y() <= point.Y())) { | 
|  | float vt = (point.Y() - vertex1.Y()) / (vertex2.Y() - vertex1.Y()); | 
|  | if (point.X() < vertex1.X() + vt * (vertex2.X() - vertex1.X())) | 
|  | ++crossing_count; | 
|  | } | 
|  | } | 
|  | return crossing_count & 1; | 
|  | } | 
|  |  | 
|  | bool FloatPolygon::ContainsNonZero(const FloatPoint& point) const { | 
|  | int winding_number = 0; | 
|  | for (unsigned i = 0; i < NumberOfEdges(); ++i) { | 
|  | const FloatPoint& vertex1 = EdgeAt(i).Vertex1(); | 
|  | const FloatPoint& vertex2 = EdgeAt(i).Vertex2(); | 
|  | if (IsPointOnLineSegment(vertex1, vertex2, point)) | 
|  | return true; | 
|  | if (vertex2.Y() <= point.Y()) { | 
|  | if ((vertex1.Y() > point.Y()) && (LeftSide(vertex1, vertex2, point) > 0)) | 
|  | ++winding_number; | 
|  | } else if (vertex2.Y() >= point.Y()) { | 
|  | if ((vertex1.Y() <= point.Y()) && (LeftSide(vertex1, vertex2, point) < 0)) | 
|  | --winding_number; | 
|  | } | 
|  | } | 
|  | return winding_number; | 
|  | } | 
|  |  | 
|  | bool FloatPolygon::Contains(const FloatPoint& point) const { | 
|  | if (!bounding_box_.Contains(point)) | 
|  | return false; | 
|  | return (FillRule() == RULE_NONZERO) ? ContainsNonZero(point) | 
|  | : ContainsEvenOdd(point); | 
|  | } | 
|  |  | 
|  | bool VertexPair::Intersection(const VertexPair& other, | 
|  | FloatPoint& point) const { | 
|  | // See: http://paulbourke.net/geometry/pointlineplane/, | 
|  | // "Intersection point of two lines in 2 dimensions" | 
|  |  | 
|  | const FloatSize& this_delta = Vertex2() - Vertex1(); | 
|  | const FloatSize& other_delta = other.Vertex2() - other.Vertex1(); | 
|  | float denominator = Determinant(this_delta, other_delta); | 
|  | if (!denominator) | 
|  | return false; | 
|  |  | 
|  | // The two line segments: "this" vertex1,vertex2 and "other" vertex1,vertex2, | 
|  | // have been defined in parametric form. Each point on the line segment is: | 
|  | // vertex1 + u * (vertex2 - vertex1), when 0 <= u <= 1. We're computing the | 
|  | // values of u for each line at their intersection point. | 
|  |  | 
|  | const FloatSize& vertex1_delta = Vertex1() - other.Vertex1(); | 
|  | float u_this_line = Determinant(other_delta, vertex1_delta) / denominator; | 
|  | float u_other_line = Determinant(this_delta, vertex1_delta) / denominator; | 
|  |  | 
|  | if (u_this_line < 0 || u_other_line < 0 || u_this_line > 1 || | 
|  | u_other_line > 1) | 
|  | return false; | 
|  |  | 
|  | point = Vertex1() + u_this_line * this_delta; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | }  // namespace blink |