|  | /* | 
|  | * Copyright 2012 Google Inc. | 
|  | * | 
|  | * Use of this source code is governed by a BSD-style license that can be | 
|  | * found in the LICENSE file. | 
|  | */ | 
|  | #include "CurveIntersection.h" | 
|  | #include "CurveUtilities.h" | 
|  | #include "IntersectionUtilities.h" | 
|  |  | 
|  | /* Given a cubic, find the convex hull described by the end and control points. | 
|  | The hull may have 3 or 4 points. Cubics that degenerate into a point or line | 
|  | are not considered. | 
|  |  | 
|  | The hull is computed by assuming that three points, if unique and non-linear, | 
|  | form a triangle. The fourth point may replace one of the first three, may be | 
|  | discarded if in the triangle or on an edge, or may be inserted between any of | 
|  | the three to form a convex quadralateral. | 
|  |  | 
|  | The indices returned in order describe the convex hull. | 
|  | */ | 
|  | int convex_hull(const Cubic& cubic, char order[4]) { | 
|  | size_t index; | 
|  | // find top point | 
|  | size_t yMin = 0; | 
|  | for (index = 1; index < 4; ++index) { | 
|  | if (cubic[yMin].y > cubic[index].y || (cubic[yMin].y == cubic[index].y | 
|  | && cubic[yMin].x > cubic[index].x)) { | 
|  | yMin = index; | 
|  | } | 
|  | } | 
|  | order[0] = yMin; | 
|  | int midX = -1; | 
|  | int backupYMin = -1; | 
|  | for (int pass = 0; pass < 2; ++pass) { | 
|  | for (index = 0; index < 4; ++index) { | 
|  | if (index == yMin) { | 
|  | continue; | 
|  | } | 
|  | // rotate line from (yMin, index) to axis | 
|  | // see if remaining two points are both above or below | 
|  | // use this to find mid | 
|  | int mask = other_two(yMin, index); | 
|  | int side1 = yMin ^ mask; | 
|  | int side2 = index ^ mask; | 
|  | Cubic rotPath; | 
|  | if (!rotate(cubic, yMin, index, rotPath)) { // ! if cbc[yMin]==cbc[idx] | 
|  | order[1] = side1; | 
|  | order[2] = side2; | 
|  | return 3; | 
|  | } | 
|  | int sides = side(rotPath[side1].y - rotPath[yMin].y); | 
|  | sides ^= side(rotPath[side2].y - rotPath[yMin].y); | 
|  | if (sides == 2) { // '2' means one remaining point <0, one >0 | 
|  | if (midX >= 0) { | 
|  | printf("%s unexpected mid\n", __FUNCTION__); // there can be only one mid | 
|  | } | 
|  | midX = index; | 
|  | } else if (sides == 0) { // '0' means both to one side or the other | 
|  | backupYMin = index; | 
|  | } | 
|  | } | 
|  | if (midX >= 0) { | 
|  | break; | 
|  | } | 
|  | if (backupYMin < 0) { | 
|  | break; | 
|  | } | 
|  | yMin = backupYMin; | 
|  | backupYMin = -1; | 
|  | } | 
|  | if (midX < 0) { | 
|  | midX = yMin ^ 3; // choose any other point | 
|  | } | 
|  | int mask = other_two(yMin, midX); | 
|  | int least = yMin ^ mask; | 
|  | int most = midX ^ mask; | 
|  | order[0] = yMin; | 
|  | order[1] = least; | 
|  |  | 
|  | // see if mid value is on same side of line (least, most) as yMin | 
|  | Cubic midPath; | 
|  | if (!rotate(cubic, least, most, midPath)) { // ! if cbc[least]==cbc[most] | 
|  | order[2] = midX; | 
|  | return 3; | 
|  | } | 
|  | int midSides = side(midPath[yMin].y - midPath[least].y); | 
|  | midSides ^= side(midPath[midX].y - midPath[least].y); | 
|  | if (midSides != 2) {  // if mid point is not between | 
|  | order[2] = most; | 
|  | return 3; // result is a triangle | 
|  | } | 
|  | order[2] = midX; | 
|  | order[3] = most; | 
|  | return 4; // result is a quadralateral | 
|  | } | 
|  |  | 
|  | /* Find the convex hull for cubics with the x-axis interval regularly spaced. | 
|  | Cubics computed as distance functions are formed this way. | 
|  |  | 
|  | connectTo0[0], connectTo0[1] are the point indices that cubic[0] connects to. | 
|  | connectTo3[0], connectTo3[1] are the point indices that cubic[3] connects to. | 
|  |  | 
|  | Returns true if cubic[1] to cubic[2] also forms part of the hull. | 
|  | */ | 
|  | bool convex_x_hull(const Cubic& cubic, char connectTo0[2], char connectTo3[2]) { | 
|  | double projectedY[4]; | 
|  | projectedY[0] = 0; | 
|  | int index; | 
|  | for (index = 1; index < 4; ++index) { | 
|  | projectedY[index] = (cubic[index].y - cubic[0].y) * (3.0 / index); | 
|  | } | 
|  | int lower0Index = 1; | 
|  | int upper0Index = 1; | 
|  | for (index = 2; index < 4; ++index) { | 
|  | if (approximately_greater_or_equal(projectedY[lower0Index], projectedY[index])) { | 
|  | lower0Index = index; | 
|  | } | 
|  | if (approximately_lesser_or_equal(projectedY[upper0Index], projectedY[index])) { | 
|  | upper0Index = index; | 
|  | } | 
|  | } | 
|  | connectTo0[0] = lower0Index; | 
|  | connectTo0[1] = upper0Index; | 
|  | for (index = 0; index < 3; ++index) { | 
|  | projectedY[index] = (cubic[3].y - cubic[index].y) * (3.0 / (3 - index)); | 
|  | } | 
|  | projectedY[3] = 0; | 
|  | int lower3Index = 2; | 
|  | int upper3Index = 2; | 
|  | for (index = 1; index > -1; --index) { | 
|  | if (approximately_greater_or_equal(projectedY[lower3Index], projectedY[index])) { | 
|  | lower3Index = index; | 
|  | } | 
|  | if (approximately_lesser_or_equal(projectedY[upper3Index], projectedY[index])) { | 
|  | upper3Index = index; | 
|  | } | 
|  | } | 
|  | connectTo3[0] = lower3Index; | 
|  | connectTo3[1] = upper3Index; | 
|  | return (1 << lower0Index | 1 << upper0Index | 
|  | | 1 << lower3Index | 1 << upper3Index) == 0x0F; | 
|  | } |