/*
|
* Copyright 2012 Google Inc.
|
*
|
* Use of this source code is governed by a BSD-style license that can be
|
* found in the LICENSE file.
|
*/
|
#ifndef SkIntersections_DEFINE
|
#define SkIntersections_DEFINE
|
|
#include "SkPathOpsConic.h"
|
#include "SkPathOpsCubic.h"
|
#include "SkPathOpsLine.h"
|
#include "SkPathOpsPoint.h"
|
#include "SkPathOpsQuad.h"
|
|
class SkIntersections {
|
public:
|
SkIntersections(SkDEBUGCODE(SkOpGlobalState* globalState = nullptr))
|
: fSwap(0)
|
#ifdef SK_DEBUG
|
SkDEBUGPARAMS(fDebugGlobalState(globalState))
|
, fDepth(0)
|
#endif
|
{
|
sk_bzero(fPt, sizeof(fPt));
|
sk_bzero(fPt2, sizeof(fPt2));
|
sk_bzero(fT, sizeof(fT));
|
sk_bzero(fNearlySame, sizeof(fNearlySame));
|
#if DEBUG_T_SECT_LOOP_COUNT
|
sk_bzero(fDebugLoopCount, sizeof(fDebugLoopCount));
|
#endif
|
reset();
|
fMax = 0; // require that the caller set the max
|
}
|
|
class TArray {
|
public:
|
explicit TArray(const double ts[10]) : fTArray(ts) {}
|
double operator[](int n) const {
|
return fTArray[n];
|
}
|
const double* fTArray;
|
};
|
TArray operator[](int n) const { return TArray(fT[n]); }
|
|
void allowNear(bool nearAllowed) {
|
fAllowNear = nearAllowed;
|
}
|
|
void clearCoincidence(int index) {
|
SkASSERT(index >= 0);
|
int bit = 1 << index;
|
fIsCoincident[0] &= ~bit;
|
fIsCoincident[1] &= ~bit;
|
}
|
|
int conicHorizontal(const SkPoint a[3], SkScalar weight, SkScalar left, SkScalar right,
|
SkScalar y, bool flipped) {
|
SkDConic conic;
|
conic.set(a, weight);
|
fMax = 2;
|
return horizontal(conic, left, right, y, flipped);
|
}
|
|
int conicVertical(const SkPoint a[3], SkScalar weight, SkScalar top, SkScalar bottom,
|
SkScalar x, bool flipped) {
|
SkDConic conic;
|
conic.set(a, weight);
|
fMax = 2;
|
return vertical(conic, top, bottom, x, flipped);
|
}
|
|
int conicLine(const SkPoint a[3], SkScalar weight, const SkPoint b[2]) {
|
SkDConic conic;
|
conic.set(a, weight);
|
SkDLine line;
|
line.set(b);
|
fMax = 3; // 2; permit small coincident segment + non-coincident intersection
|
return intersect(conic, line);
|
}
|
|
int cubicHorizontal(const SkPoint a[4], SkScalar left, SkScalar right, SkScalar y,
|
bool flipped) {
|
SkDCubic cubic;
|
cubic.set(a);
|
fMax = 3;
|
return horizontal(cubic, left, right, y, flipped);
|
}
|
|
int cubicVertical(const SkPoint a[4], SkScalar top, SkScalar bottom, SkScalar x, bool flipped) {
|
SkDCubic cubic;
|
cubic.set(a);
|
fMax = 3;
|
return vertical(cubic, top, bottom, x, flipped);
|
}
|
|
int cubicLine(const SkPoint a[4], const SkPoint b[2]) {
|
SkDCubic cubic;
|
cubic.set(a);
|
SkDLine line;
|
line.set(b);
|
fMax = 3;
|
return intersect(cubic, line);
|
}
|
|
#ifdef SK_DEBUG
|
SkOpGlobalState* globalState() const { return fDebugGlobalState; }
|
#endif
|
|
bool hasT(double t) const {
|
SkASSERT(t == 0 || t == 1);
|
return fUsed > 0 && (t == 0 ? fT[0][0] == 0 : fT[0][fUsed - 1] == 1);
|
}
|
|
bool hasOppT(double t) const {
|
SkASSERT(t == 0 || t == 1);
|
return fUsed > 0 && (fT[1][0] == t || fT[1][fUsed - 1] == t);
|
}
|
|
int insertSwap(double one, double two, const SkDPoint& pt) {
|
if (fSwap) {
|
return insert(two, one, pt);
|
} else {
|
return insert(one, two, pt);
|
}
|
}
|
|
bool isCoincident(int index) {
|
return (fIsCoincident[0] & 1 << index) != 0;
|
}
|
|
int lineHorizontal(const SkPoint a[2], SkScalar left, SkScalar right, SkScalar y,
|
bool flipped) {
|
SkDLine line;
|
line.set(a);
|
fMax = 2;
|
return horizontal(line, left, right, y, flipped);
|
}
|
|
int lineVertical(const SkPoint a[2], SkScalar top, SkScalar bottom, SkScalar x, bool flipped) {
|
SkDLine line;
|
line.set(a);
|
fMax = 2;
|
return vertical(line, top, bottom, x, flipped);
|
}
|
|
int lineLine(const SkPoint a[2], const SkPoint b[2]) {
|
SkDLine aLine, bLine;
|
aLine.set(a);
|
bLine.set(b);
|
fMax = 2;
|
return intersect(aLine, bLine);
|
}
|
|
bool nearlySame(int index) const {
|
SkASSERT(index == 0 || index == 1);
|
return fNearlySame[index];
|
}
|
|
const SkDPoint& pt(int index) const {
|
return fPt[index];
|
}
|
|
const SkDPoint& pt2(int index) const {
|
return fPt2[index];
|
}
|
|
int quadHorizontal(const SkPoint a[3], SkScalar left, SkScalar right, SkScalar y,
|
bool flipped) {
|
SkDQuad quad;
|
quad.set(a);
|
fMax = 2;
|
return horizontal(quad, left, right, y, flipped);
|
}
|
|
int quadVertical(const SkPoint a[3], SkScalar top, SkScalar bottom, SkScalar x, bool flipped) {
|
SkDQuad quad;
|
quad.set(a);
|
fMax = 2;
|
return vertical(quad, top, bottom, x, flipped);
|
}
|
|
int quadLine(const SkPoint a[3], const SkPoint b[2]) {
|
SkDQuad quad;
|
quad.set(a);
|
SkDLine line;
|
line.set(b);
|
return intersect(quad, line);
|
}
|
|
// leaves swap, max alone
|
void reset() {
|
fAllowNear = true;
|
fUsed = 0;
|
sk_bzero(fIsCoincident, sizeof(fIsCoincident));
|
}
|
|
void set(bool swap, int tIndex, double t) {
|
fT[(int) swap][tIndex] = t;
|
}
|
|
void setMax(int max) {
|
SkASSERT(max <= (int) SK_ARRAY_COUNT(fPt));
|
fMax = max;
|
}
|
|
void swap() {
|
fSwap ^= true;
|
}
|
|
bool swapped() const {
|
return fSwap;
|
}
|
|
int used() const {
|
return fUsed;
|
}
|
|
void downDepth() {
|
SkASSERT(--fDepth >= 0);
|
}
|
|
bool unBumpT(int index) {
|
SkASSERT(fUsed == 1);
|
fT[0][index] = fT[0][index] * (1 + BUMP_EPSILON * 2) - BUMP_EPSILON;
|
if (!between(0, fT[0][index], 1)) {
|
fUsed = 0;
|
return false;
|
}
|
return true;
|
}
|
|
void upDepth() {
|
SkASSERT(++fDepth < 16);
|
}
|
|
void alignQuadPts(const SkPoint a[3], const SkPoint b[3]);
|
int cleanUpCoincidence();
|
int closestTo(double rangeStart, double rangeEnd, const SkDPoint& testPt, double* dist) const;
|
void cubicInsert(double one, double two, const SkDPoint& pt, const SkDCubic& c1,
|
const SkDCubic& c2);
|
void flip();
|
int horizontal(const SkDLine&, double left, double right, double y, bool flipped);
|
int horizontal(const SkDQuad&, double left, double right, double y, bool flipped);
|
int horizontal(const SkDQuad&, double left, double right, double y, double tRange[2]);
|
int horizontal(const SkDCubic&, double y, double tRange[3]);
|
int horizontal(const SkDConic&, double left, double right, double y, bool flipped);
|
int horizontal(const SkDCubic&, double left, double right, double y, bool flipped);
|
int horizontal(const SkDCubic&, double left, double right, double y, double tRange[3]);
|
static double HorizontalIntercept(const SkDLine& line, double y);
|
static int HorizontalIntercept(const SkDQuad& quad, SkScalar y, double* roots);
|
static int HorizontalIntercept(const SkDConic& conic, SkScalar y, double* roots);
|
// FIXME : does not respect swap
|
int insert(double one, double two, const SkDPoint& pt);
|
void insertNear(double one, double two, const SkDPoint& pt1, const SkDPoint& pt2);
|
// start if index == 0 : end if index == 1
|
int insertCoincident(double one, double two, const SkDPoint& pt);
|
int intersect(const SkDLine&, const SkDLine&);
|
int intersect(const SkDQuad&, const SkDLine&);
|
int intersect(const SkDQuad&, const SkDQuad&);
|
int intersect(const SkDConic&, const SkDLine&);
|
int intersect(const SkDConic&, const SkDQuad&);
|
int intersect(const SkDConic&, const SkDConic&);
|
int intersect(const SkDCubic&, const SkDLine&);
|
int intersect(const SkDCubic&, const SkDQuad&);
|
int intersect(const SkDCubic&, const SkDConic&);
|
int intersect(const SkDCubic&, const SkDCubic&);
|
int intersectRay(const SkDLine&, const SkDLine&);
|
int intersectRay(const SkDQuad&, const SkDLine&);
|
int intersectRay(const SkDConic&, const SkDLine&);
|
int intersectRay(const SkDCubic&, const SkDLine&);
|
int intersectRay(const SkTCurve& tCurve, const SkDLine& line) {
|
return tCurve.intersectRay(this, line);
|
}
|
|
void merge(const SkIntersections& , int , const SkIntersections& , int );
|
int mostOutside(double rangeStart, double rangeEnd, const SkDPoint& origin) const;
|
void removeOne(int index);
|
void setCoincident(int index);
|
int vertical(const SkDLine&, double top, double bottom, double x, bool flipped);
|
int vertical(const SkDQuad&, double top, double bottom, double x, bool flipped);
|
int vertical(const SkDConic&, double top, double bottom, double x, bool flipped);
|
int vertical(const SkDCubic&, double top, double bottom, double x, bool flipped);
|
static double VerticalIntercept(const SkDLine& line, double x);
|
static int VerticalIntercept(const SkDQuad& quad, SkScalar x, double* roots);
|
static int VerticalIntercept(const SkDConic& conic, SkScalar x, double* roots);
|
|
int depth() const {
|
#ifdef SK_DEBUG
|
return fDepth;
|
#else
|
return 0;
|
#endif
|
}
|
|
enum DebugLoop {
|
kIterations_DebugLoop,
|
kCoinCheck_DebugLoop,
|
kComputePerp_DebugLoop,
|
};
|
|
void debugBumpLoopCount(DebugLoop );
|
int debugCoincidentUsed() const;
|
int debugLoopCount(DebugLoop ) const;
|
void debugResetLoopCount();
|
void dump() const; // implemented for testing only
|
|
private:
|
bool cubicCheckCoincidence(const SkDCubic& c1, const SkDCubic& c2);
|
bool cubicExactEnd(const SkDCubic& cubic1, bool start, const SkDCubic& cubic2);
|
void cubicNearEnd(const SkDCubic& cubic1, bool start, const SkDCubic& cubic2, const SkDRect& );
|
void cleanUpParallelLines(bool parallel);
|
void computePoints(const SkDLine& line, int used);
|
|
SkDPoint fPt[13]; // FIXME: since scans store points as SkPoint, this should also
|
SkDPoint fPt2[2]; // used by nearly same to store alternate intersection point
|
double fT[2][13];
|
uint16_t fIsCoincident[2]; // bit set for each curve's coincident T
|
bool fNearlySame[2]; // true if end points nearly match
|
unsigned char fUsed;
|
unsigned char fMax;
|
bool fAllowNear;
|
bool fSwap;
|
#ifdef SK_DEBUG
|
SkOpGlobalState* fDebugGlobalState;
|
int fDepth;
|
#endif
|
#if DEBUG_T_SECT_LOOP_COUNT
|
int fDebugLoopCount[3];
|
#endif
|
};
|
|
#endif
|