//////////////////////////////////////////////////////////////////////////// //--------------------------------- REVISIONS ------------------------------ // Date Name Tracking # Description // --------- ------------------- ------------- ---------------------- // 13JUN2009 James Shen Initial Creation //////////////////////////////////////////////////////////////////////////// private void Next(bool doNext) { int level; if (_holdIndex >= _holdEnd) { if (doNext) { _src.Next(); } if (_src.IsDone()) { _done = true; return; } _holdType = _src.CurrentSegment(_intHold); for (int i = 0; i < _intHold.Length; i++) { _hold[i] = _intHold[i]; } _levelIndex = 0; _levels[0] = 0; } switch (_holdType) { case SEG_MOVETO: case SEG_LINETO: _curx = _hold[0]; _cury = _hold[1]; if (_holdType == SEG_MOVETO) { _movx = _curx; _movy = _cury; } _holdIndex = 0; _holdEnd = 0; break; case SEG_CLOSE: _curx = _movx; _cury = _movy; _holdIndex = 0; _holdEnd = 0; break; case SEG_QUADTO: if (_holdIndex >= _holdEnd) { // Move the coordinates to the end of the array. _holdIndex = _hold.Length - 6; _holdEnd = _hold.Length - 2; _hold[_holdIndex + 0] = _curx; _hold[_holdIndex + 1] = _cury; _hold[_holdIndex + 2] = _hold[0]; _hold[_holdIndex + 3] = _hold[1]; _hold[_holdIndex + 4] = _curx = _hold[2]; _hold[_holdIndex + 5] = _cury = _hold[3]; } level = _levels[_levelIndex]; while (level < _limit) { for (int i = 0; i < _intHold.Length; i++) { _intHold[i] = (int)(_hold[i] + .5); } if (QuadCurve.GetFlatnessSq(_intHold, _holdIndex) < _squareflat) { break; } EnsureHoldCapacity(4); QuadCurve.Subdivide(_hold, _holdIndex, _hold, _holdIndex - 4, _hold, _holdIndex); _holdIndex -= 4; // Now that we have subdivided, we have constructed // two curves of one depth lower than the original // curve. One of those curves is in the place of // the former curve and one of them is in the next // set of held coordinate slots. We now set both // curves level values to the next higher level. level++; _levels[_levelIndex] = level; _levelIndex++; _levels[_levelIndex] = level; } // This curve segment is flat enough, or it is too deep // in recursion levels to try to flatten any more. The // two coordinates at holdIndex+4 and holdIndex+5 now // contain the endpoint of the curve which can be the // endpoint of an approximating line segment. _holdIndex += 4; _levelIndex--; break; case SEG_CUBICTO: if (_holdIndex >= _holdEnd) { // Move the coordinates to the end of the array. _holdIndex = _hold.Length - 8; _holdEnd = _hold.Length - 2; _hold[_holdIndex + 0] = _curx; _hold[_holdIndex + 1] = _cury; _hold[_holdIndex + 2] = _hold[0]; _hold[_holdIndex + 3] = _hold[1]; _hold[_holdIndex + 4] = _hold[2]; _hold[_holdIndex + 5] = _hold[3]; _hold[_holdIndex + 6] = _curx = _hold[4]; _hold[_holdIndex + 7] = _cury = _hold[5]; } level = _levels[_levelIndex]; while (level < _limit) { for (int i = 0; i < _intHold.Length; i++) { _intHold[i] = (int)(_hold[i] + .5); } if (CubicCurve.GetFlatnessSq(_intHold, _holdIndex) < _squareflat) { break; } EnsureHoldCapacity(6); CubicCurve.Subdivide(_hold, _holdIndex, _hold, _holdIndex - 6, _hold, _holdIndex); _holdIndex -= 6; // Now that we have subdivided, we have constructed // two curves of one depth lower than the original // curve. One of those curves is in the place of // the former curve and one of them is in the next // set of held coordinate slots. We now set both // curves level values to the next higher level. level++; _levels[_levelIndex] = level; _levelIndex++; _levels[_levelIndex] = level; } // This curve segment is flat enough, or it is too deep // in recursion levels to try to flatten any more. The // two coordinates at holdIndex+6 and holdIndex+7 now // contain the endpoint of the curve which can be the // endpoint of an approximating line segment. _holdIndex += 6; _levelIndex--; break; } }
/** * Calculates the number of times the given path * crosses the ray extending to the right from (px,py). * If the point lies on a part of the path, * then no crossings are counted for that intersection. * +1 is added for each crossing where the Y coordinate is increasing * -1 is added for each crossing where the Y coordinate is decreasing * The return Value is the sum of all crossings for every segment in * the path. * The path must start with a SEG_MOVETO, otherwise an exception is * thrown. * The caller must check p[xy] for NaN values. * The caller may also reject infinite p[xy] values as well. */ public static int PointCrossingsForPath(PathIterator pi, double px, double py) { if (pi.IsDone()) { return 0; } int[] coords = new int[6]; if (pi.CurrentSegment(coords) != PathIterator.SEG_MOVETO) { throw new IllegalPathStateException("missing initial moveto " + "in path definition"); } pi.Next(); double movx = coords[0]; double movy = coords[1]; double curx = movx; double cury = movy; int crossings = 0; while (!pi.IsDone()) { double endx; double endy; switch (pi.CurrentSegment(coords)) { case PathIterator.SEG_MOVETO: if (cury != movy) { crossings += PointCrossingsForLine(px, py, curx, cury, movx, movy); } movx = curx = coords[0]; movy = cury = coords[1]; break; case PathIterator.SEG_LINETO: endx = coords[0]; endy = coords[1]; crossings += PointCrossingsForLine(px, py, curx, cury, endx, endy); curx = endx; cury = endy; break; case PathIterator.SEG_QUADTO: endx = coords[2]; endy = coords[3]; crossings += PointCrossingsForQuad(px, py, curx, cury, coords[0], coords[1], endx, endy, 0); curx = endx; cury = endy; break; case PathIterator.SEG_CUBICTO: endx = coords[4]; endy = coords[5]; crossings += PointCrossingsForCubic(px, py, curx, cury, coords[0], coords[1], coords[2], coords[3], endx, endy, 0); curx = endx; cury = endy; break; case PathIterator.SEG_CLOSE: if (cury != movy) { crossings += PointCrossingsForLine(px, py, curx, cury, movx, movy); } curx = movx; cury = movy; break; } pi.Next(); } if (cury != movy) { crossings += PointCrossingsForLine(px, py, curx, cury, movx, movy); } return crossings; }
/** * Accumulate the number of times the path crosses the shadow * extending to the right of the rectangle. See the comment * for the RECT_INTERSECTS constant for more complete details. * The return Value is the sum of all crossings for both the * top and bottom of the shadow for every segment in the path, * or the special Value RECT_INTERSECTS if the path ever enters * the interior of the rectangle. * The path must start with a SEG_MOVETO, otherwise an exception is * thrown. * The caller must check r[xy]{Min,Max} for NaN values. */ public static int RectCrossingsForPath(PathIterator pi, double rxmin, double rymin, double rxmax, double rymax) { if (rxmax <= rxmin || rymax <= rymin) { return 0; } if (pi.IsDone()) { return 0; } int[] coords = new int[6]; if (pi.CurrentSegment(coords) != PathIterator.SEG_MOVETO) { throw new IllegalPathStateException("missing initial moveto " + "in path definition"); } pi.Next(); double movx, movy; double curx = movx = coords[0]; double cury = movy = coords[1]; int crossings = 0; while (crossings != RECT_INTERSECTS && !pi.IsDone()) { double endx; double endy; switch (pi.CurrentSegment(coords)) { case PathIterator.SEG_MOVETO: if (curx != movx || cury != movy) { crossings = RectCrossingsForLine(crossings, rxmin, rymin, rxmax, rymax, curx, cury, movx, movy); } // Count should always be a multiple of 2 here. // assert((crossings & 1) != 0); movx = curx = coords[0]; movy = cury = coords[1]; break; case PathIterator.SEG_LINETO: endx = coords[0]; endy = coords[1]; crossings = RectCrossingsForLine(crossings, rxmin, rymin, rxmax, rymax, curx, cury, endx, endy); curx = endx; cury = endy; break; case PathIterator.SEG_QUADTO: endx = coords[2]; endy = coords[3]; crossings = RectCrossingsForQuad(crossings, rxmin, rymin, rxmax, rymax, curx, cury, coords[0], coords[1], endx, endy, 0); curx = endx; cury = endy; break; case PathIterator.SEG_CUBICTO: endx = coords[4]; endy = coords[5]; crossings = RectCrossingsForCubic(crossings, rxmin, rymin, rxmax, rymax, curx, cury, coords[0], coords[1], coords[2], coords[3], endx, endy, 0); curx = endx; cury = endy; break; case PathIterator.SEG_CLOSE: if (curx != movx || cury != movy) { crossings = RectCrossingsForLine(crossings, rxmin, rymin, rxmax, rymax, curx, cury, movx, movy); } curx = movx; cury = movy; // Count should always be a multiple of 2 here. // assert((crossings & 1) != 0); break; } pi.Next(); } if (crossings != RECT_INTERSECTS && (curx != movx || cury != movy)) { crossings = RectCrossingsForLine(crossings, rxmin, rymin, rxmax, rymax, curx, cury, movx, movy); } // Count should always be a multiple of 2 here. // assert((crossings & 1) != 0); return crossings; }
//////////////////////////////////////////////////////////////////////////// //--------------------------------- REVISIONS ------------------------------ // Date Name Tracking # Description // --------- ------------------- ------------- ---------------------- // 13JUN2009 James Shen Initial Creation //////////////////////////////////////////////////////////////////////////// private static ArrayList PathToCurves(PathIterator pi) { ArrayList curves = new ArrayList(); int windingRule = pi.GetWindingRule(); // coords array is big enough for holding: // coordinates returned from currentSegment (6) // OR // two subdivided quadratic curves (2+4+4=10) // AND // 0-1 horizontal splitting parameters // OR // 2 parametric equation derivative coefficients // OR // three subdivided cubic curves (2+6+6+6=20) // AND // 0-2 horizontal splitting parameters // OR // 3 parametric equation derivative coefficients var coords = new int[23]; double movx = 0, movy = 0; double curx = 0, cury = 0; while (!pi.IsDone()) { double newx; double newy; switch (pi.CurrentSegment(coords)) { case PathIterator.SEG_MOVETO: Curve.InsertLine(curves, curx, cury, movx, movy); curx = movx = coords[0]; cury = movy = coords[1]; Curve.InsertMove(curves, movx, movy); break; case PathIterator.SEG_LINETO: newx = coords[0]; newy = coords[1]; Curve.InsertLine(curves, curx, cury, newx, newy); curx = newx; cury = newy; break; case PathIterator.SEG_QUADTO: { newx = coords[2]; newy = coords[3]; var dblCoords = new double[coords.Length]; for (int i = 0; i < coords.Length; i++) { dblCoords[i] = coords[i]; } Curve.InsertQuad(curves, curx, cury, dblCoords); curx = newx; cury = newy; } break; case PathIterator.SEG_CUBICTO: { newx = coords[4]; newy = coords[5]; var dblCoords = new double[coords.Length]; for (int i = 0; i < coords.Length; i++) { dblCoords[i] = coords[i]; } Curve.InsertCubic(curves, curx, cury, dblCoords); curx = newx; cury = newy; } break; case PathIterator.SEG_CLOSE: Curve.InsertLine(curves, curx, cury, movx, movy); curx = movx; cury = movy; break; } pi.Next(); } Curve.InsertLine(curves, curx, cury, movx, movy); AreaOp op; if (windingRule == PathIterator.WIND_EVEN_ODD) { op = new AreaOp.EoWindOp(); } else { op = new AreaOp.NzWindOp(); } return(op.Calculate(curves, EmptyCurves)); }
public static Crossings FindCrossings(PathIterator pi, double xlo, double ylo, double xhi, double yhi) { Crossings cross; if (pi.GetWindingRule() == PathIterator.WIND_EVEN_ODD) { cross = new EvenOdd(xlo, ylo, xhi, yhi); } else { cross = new NonZero(xlo, ylo, xhi, yhi); } // coords array is big enough for holding: // coordinates returned from currentSegment (6) // OR // two subdivided quadratic curves (2+4+4=10) // AND // 0-1 horizontal splitting parameters // OR // 2 parametric equation derivative coefficients // OR // three subdivided cubic curves (2+6+6+6=20) // AND // 0-2 horizontal splitting parameters // OR // 3 parametric equation derivative coefficients var coords = new int[23]; double movx = 0; double movy = 0; double curx = 0; double cury = 0; while (!pi.IsDone()) { int type = pi.CurrentSegment(coords); double newx; double newy; switch (type) { case PathIterator.SEG_MOVETO: if (movy != cury && cross.AccumulateLine(curx, cury, movx, movy)) { return(null); } movx = curx = coords[0]; movy = cury = coords[1]; break; case PathIterator.SEG_LINETO: newx = coords[0]; newy = coords[1]; if (cross.AccumulateLine(curx, cury, newx, newy)) { return(null); } curx = newx; cury = newy; break; case PathIterator.SEG_QUADTO: { newx = coords[2]; newy = coords[3]; var dblCoords = new double[coords.Length]; for (int i = 0; i < coords.Length; i++) { dblCoords[i] = coords[i]; } if (cross.AccumulateQuad(curx, cury, dblCoords)) { return(null); } curx = newx; cury = newy; } break; case PathIterator.SEG_CUBICTO: { newx = coords[4]; newy = coords[5]; var dblCoords = new double[coords.Length]; for (int i = 0; i < coords.Length; i++) { dblCoords[i] = coords[i]; } if (cross.AccumulateCubic(curx, cury, dblCoords)) { return(null); } curx = newx; cury = newy; break; } case PathIterator.SEG_CLOSE: if (movy != cury && cross.AccumulateLine(curx, cury, movx, movy)) { return(null); } curx = movx; cury = movy; break; } pi.Next(); } if (movy != cury) { if (cross.AccumulateLine(curx, cury, movx, movy)) { return(null); } } return(cross); }
public static Crossings FindCrossings(PathIterator pi, double xlo, double ylo, double xhi, double yhi) { Crossings cross; if (pi.GetWindingRule() == PathIterator.WIND_EVEN_ODD) { cross = new EvenOdd(xlo, ylo, xhi, yhi); } else { cross = new NonZero(xlo, ylo, xhi, yhi); } // coords array is big enough for holding: // coordinates returned from currentSegment (6) // OR // two subdivided quadratic curves (2+4+4=10) // AND // 0-1 horizontal splitting parameters // OR // 2 parametric equation derivative coefficients // OR // three subdivided cubic curves (2+6+6+6=20) // AND // 0-2 horizontal splitting parameters // OR // 3 parametric equation derivative coefficients var coords = new int[23]; double movx = 0; double movy = 0; double curx = 0; double cury = 0; while (!pi.IsDone()) { int type = pi.CurrentSegment(coords); double newx; double newy; switch (type) { case PathIterator.SEG_MOVETO: if (movy != cury && cross.AccumulateLine(curx, cury, movx, movy)) { return null; } movx = curx = coords[0]; movy = cury = coords[1]; break; case PathIterator.SEG_LINETO: newx = coords[0]; newy = coords[1]; if (cross.AccumulateLine(curx, cury, newx, newy)) { return null; } curx = newx; cury = newy; break; case PathIterator.SEG_QUADTO: { newx = coords[2]; newy = coords[3]; var dblCoords = new double[coords.Length]; for (int i = 0; i < coords.Length; i++) { dblCoords[i] = coords[i]; } if (cross.AccumulateQuad(curx, cury, dblCoords)) { return null; } curx = newx; cury = newy; } break; case PathIterator.SEG_CUBICTO: { newx = coords[4]; newy = coords[5]; var dblCoords = new double[coords.Length]; for (int i = 0; i < coords.Length; i++) { dblCoords[i] = coords[i]; } if (cross.AccumulateCubic(curx, cury, dblCoords)) { return null; } curx = newx; cury = newy; break; } case PathIterator.SEG_CLOSE: if (movy != cury && cross.AccumulateLine(curx, cury, movx, movy)) { return null; } curx = movx; cury = movy; break; } pi.Next(); } if (movy != cury) { if (cross.AccumulateLine(curx, cury, movx, movy)) { return null; } } return cross; }
//////////////////////////////////////////////////////////////////////////// //--------------------------------- REVISIONS ------------------------------ // Date Name Tracking # Description // --------- ------------------- ------------- ---------------------- // 13JUN2009 James Shen Initial Creation //////////////////////////////////////////////////////////////////////////// private static ArrayList PathToCurves(PathIterator pi) { ArrayList curves = new ArrayList(); int windingRule = pi.GetWindingRule(); // coords array is big enough for holding: // coordinates returned from currentSegment (6) // OR // two subdivided quadratic curves (2+4+4=10) // AND // 0-1 horizontal splitting parameters // OR // 2 parametric equation derivative coefficients // OR // three subdivided cubic curves (2+6+6+6=20) // AND // 0-2 horizontal splitting parameters // OR // 3 parametric equation derivative coefficients var coords = new int[23]; double movx = 0, movy = 0; double curx = 0, cury = 0; while (!pi.IsDone()) { double newx; double newy; switch (pi.CurrentSegment(coords)) { case PathIterator.SEG_MOVETO: Curve.InsertLine(curves, curx, cury, movx, movy); curx = movx = coords[0]; cury = movy = coords[1]; Curve.InsertMove(curves, movx, movy); break; case PathIterator.SEG_LINETO: newx = coords[0]; newy = coords[1]; Curve.InsertLine(curves, curx, cury, newx, newy); curx = newx; cury = newy; break; case PathIterator.SEG_QUADTO: { newx = coords[2]; newy = coords[3]; var dblCoords = new double[coords.Length]; for (int i = 0; i < coords.Length; i++) { dblCoords[i] = coords[i]; } Curve.InsertQuad(curves, curx, cury, dblCoords); curx = newx; cury = newy; } break; case PathIterator.SEG_CUBICTO: { newx = coords[4]; newy = coords[5]; var dblCoords = new double[coords.Length]; for (int i = 0; i < coords.Length; i++) { dblCoords[i] = coords[i]; } Curve.InsertCubic(curves, curx, cury, dblCoords); curx = newx; cury = newy; } break; case PathIterator.SEG_CLOSE: Curve.InsertLine(curves, curx, cury, movx, movy); curx = movx; cury = movy; break; } pi.Next(); } Curve.InsertLine(curves, curx, cury, movx, movy); AreaOp op; if (windingRule == PathIterator.WIND_EVEN_ODD) { op = new AreaOp.EoWindOp(); } else { op = new AreaOp.NzWindOp(); } return op.Calculate(curves, EmptyCurves); }
//////////////////////////////////////////////////////////////////////////// //--------------------------------- REVISIONS ------------------------------ // Date Name Tracking # Description // --------- ------------------- ------------- ---------------------- // 13JUN2009 James Shen Initial Creation //////////////////////////////////////////////////////////////////////////// /** * Appends the geometry of the specified * {@link PathIterator} object * to the path, possibly connecting the new geometry to the existing * path segments with a line segment. * If the {@code connect} parameter is {@code true} and the * path is not empty then any initial {@code moveTo} in the * geometry of the appended {@code IShape} is turned into a * {@code lineTo} segment. * If the destination coordinates of such a connecting {@code lineTo} * segment match the ending coordinates of a currently open * subpath then the segment is omitted as superfluous. * The winding rule of the specified {@code IShape} is ignored * and the appended geometry is governed by the winding * rule specified for this path. * * @param pi the {@code PathIterator} whose geometry is appended to * this path * @param connect a bool to control whether or not to turn an initial * {@code moveTo} segment into a {@code lineTo} segment * to connect the new geometry to the existing path */ public void Append(PathIterator pi, bool connect) { int[] coords = new int[6]; while (!pi.IsDone()) { switch (pi.CurrentSegment(coords)) { case SEG_MOVETO: if (!connect || _numTypes < 1 || _numCoords < 1) { MoveTo(coords[0], coords[1]); break; } if (_pointTypes[_numTypes - 1] != SEG_CLOSE && _intCoords[_numCoords - 2] == coords[0] && _intCoords[_numCoords - 1] == coords[1]) { // Collapse out initial moveto/lineto break; } LineTo(coords[0], coords[1]); break; case SEG_LINETO: LineTo(coords[0], coords[1]); break; case SEG_QUADTO: QuadTo(coords[0], coords[1], coords[2], coords[3]); break; case SEG_CUBICTO: CurveTo(coords[0], coords[1], coords[2], coords[3], coords[4], coords[5]); break; case SEG_CLOSE: ClosePath(); break; } pi.Next(); connect = false; } }