private void visitInteriorRing(LineString ring, PlanarGraph graph) { Coordinate[] pts = ring.getCoordinates(); Coordinate pt0 = pts[0]; /** * Find first point in coord list different to initial point. * Need special check since the first point may be repeated. */ Coordinate pt1 = findDifferentPoint(pts, pt0); Edge e = graph.findEdgeInSameDirection(pt0, pt1); DirectedEdge de = (DirectedEdge) graph.findEdgeEnd(e); DirectedEdge intDe = null; if (de.getLabel().getLocation(0, Position.RIGHT) == Location.INTERIOR) { intDe = de; } else if (de.getSym().getLabel().getLocation(0, Position.RIGHT) == Location.INTERIOR) { intDe = de.getSym(); } Assert.isTrue(intDe != null, "unable to find dirEdge with Interior on RHS"); this.visitLinkedDirectedEdges(intDe); }
/** * Find all edges whose label indicates that they are in the result area(s), * according to the operation being performed. Since we want polygon shells to be * oriented CW, choose dirEdges with the interior of the result on the RHS. * Mark them as being in the result. * Interior Area edges are the result of dimensional collapses. * They do not form part of the result area boundary. */ private void findResultAreaEdges(int opCode) { for (Object o : graph.getEdgeEnds()) { DirectedEdge de = (DirectedEdge) o; // mark all dirEdges with the appropriate label Label label = de.getLabel(); if (label.isArea() && !de.isInteriorAreaEdge() && isResultOfOp( label.getLocation(0, Position.RIGHT), label.getLocation(1, Position.RIGHT), opCode)) { de.setInResult(true); //Debug.print("in result "); Debug.println(de); } } }
private int getRightmostSideOfSegment(DirectedEdge de, int i) { Edge e = de.getEdge(); Coordinate coord[] = e.getCoordinates(); if (i < 0 || i + 1 >= coord.length) { return -1; } if (coord[i].y == coord[i + 1].y) { return -1; // indicates edge is parallel to x-axis } int pos = Position.LEFT; if (coord[i].y < coord[i + 1].y) { pos = Position.RIGHT; } return pos; }
private void computeRingBufferCurve(Coordinate[] inputPts, int side, OffsetSegmentGenerator segGen) { // simplify input line to improve performance double distTol = simplifyTolerance(this.distance); // ensure that correct side is simplified if (side == Position.RIGHT) { distTol = -distTol; } Coordinate[] simp = BufferInputLineSimplifier.simplify(inputPts, distTol); // Coordinate[] simp = inputPts; int n = simp.length - 1; segGen.initSideSegments(simp[n - 1], simp[0], side); for (int i = 1; i <= n; i++) { boolean addStartPoint = i != 1; segGen.addNextSegment(simp[i], addStartPoint); } segGen.closeRing(); }
/** * Adds an offset curve for a polygon ring. * The side and left and right topological location arguments * assume that the ring is oriented CW. * If the ring is in the opposite orientation, * the left and right locations must be interchanged and the side flipped. * * @param coord the coordinates of the ring (must not contain repeated points) * @param offsetDistance the distance at which to create the buffer * @param side the side of the ring on which to construct the buffer line * @param cwLeftLoc the location on the L side of the ring (if it is CW) * @param cwRightLoc the location on the R side of the ring (if it is CW) */ private void addPolygonRing(Coordinate[] coord, double offsetDistance, int side, int cwLeftLoc, int cwRightLoc) { // don't bother adding ring if it is "flat" and will disappear in the output if (offsetDistance == 0.0 && coord.length < LinearRing.MINIMUM_VALID_SIZE) { return; } int leftLoc = cwLeftLoc; int rightLoc = cwRightLoc; if (coord.length >= LinearRing.MINIMUM_VALID_SIZE && CGAlgorithms.isCCW(coord)) { leftLoc = cwRightLoc; rightLoc = cwLeftLoc; side = Position.opposite(side); } Coordinate[] curve = this.curveBuilder.getRingCurve(coord, side, offsetDistance); this.addCurve(curve, leftLoc, rightLoc); }
/** * Find all edges whose depths indicates that they are in the result area(s). * Since we want polygon shells to be * oriented CW, choose dirEdges with the interior of the result on the RHS. * Mark them as being in the result. * Interior Area edges are the result of dimensional collapses. * They do not form part of the result area boundary. */ public void findResultEdges() { for (Object aDirEdgeList : dirEdgeList) { DirectedEdge de = (DirectedEdge) aDirEdgeList; /** * Select edges which have an interior depth on the RHS * and an exterior depth on the LHS. * Note that because of weird rounding effects there may be * edges which have negative depths! Negative depths * count as "outside". */ // <FIX> - handle negative depths if (de.getDepth(Position.RIGHT) >= 1 && de.getDepth(Position.LEFT) <= 0 && !de.isInteriorAreaEdge()) { de.setInResult(true); //Debug.print("in result "); Debug.println(de); } } }
private void computeRingBufferCurve(Coordinate[] inputPts, int side, OffsetSegmentGenerator segGen) { // simplify input line to improve performance double distTol = simplifyTolerance(distance); // ensure that correct side is simplified if (side == Position.RIGHT) distTol = -distTol; Coordinate[] simp = BufferInputLineSimplifier.simplify(inputPts, distTol); // Coordinate[] simp = inputPts; int n = simp.length - 1; segGen.initSideSegments(simp[n - 1], simp[0], side); for (int i = 1; i <= n; i++) { boolean addStartPoint = i != 1; segGen.addNextSegment(simp[i], addStartPoint); } segGen.closeRing(); }
/** * Adds an offset curve for a polygon ring. * The side and left and right topological location arguments * assume that the ring is oriented CW. * If the ring is in the opposite orientation, * the left and right locations must be interchanged and the side flipped. * * @param coord the coordinates of the ring (must not contain repeated points) * @param offsetDistance the distance at which to create the buffer * @param side the side of the ring on which to construct the buffer line * @param cwLeftLoc the location on the L side of the ring (if it is CW) * @param cwRightLoc the location on the R side of the ring (if it is CW) */ private void addPolygonRing(Coordinate[] coord, double offsetDistance, int side, int cwLeftLoc, int cwRightLoc) { // don't bother adding ring if it is "flat" and will disappear in the output if (offsetDistance == 0.0 && coord.length < LinearRing.MINIMUM_VALID_SIZE) return; int leftLoc = cwLeftLoc; int rightLoc = cwRightLoc; if (coord.length >= LinearRing.MINIMUM_VALID_SIZE && CGAlgorithms.isCCW(coord)) { leftLoc = cwRightLoc; rightLoc = cwLeftLoc; side = Position.opposite(side); } Coordinate[] curve = curveBuilder.getRingCurve(coord, side, offsetDistance); addCurve(curve, leftLoc, rightLoc); }
public void addNextSegment(Coordinate p, boolean addStartPoint) { // s0-s1-s2 are the coordinates of the previous segment and the current one s0 = s1; s1 = s2; s2 = p; seg0.setCoordinates(s0, s1); computeOffsetSegment(seg0, side, distance, offset0); seg1.setCoordinates(s1, s2); computeOffsetSegment(seg1, side, distance, offset1); // do nothing if points are equal if (s1.equals(s2)) return; int orientation = CGAlgorithms.computeOrientation(s0, s1, s2); boolean outsideTurn = (orientation == CGAlgorithms.CLOCKWISE && side == Position.LEFT) || (orientation == CGAlgorithms.COUNTERCLOCKWISE && side == Position.RIGHT); if (orientation == 0) { // lines are collinear addCollinear(addStartPoint); } else if (outsideTurn) { addOutsideTurn(orientation, addStartPoint); } else { // inside turn addInsideTurn(orientation, addStartPoint); } }
/** * merge updates only the NULL attributes of this object * with the attributes of another. */ public void merge(TopologyLocation gl) { // if the src is an Area label & and the dest is not, increase the dest to be an Area if (gl.location.length > location.length) { int [] newLoc = new int[3]; newLoc[Position.ON] = location[Position.ON]; newLoc[Position.LEFT] = Location.NONE; newLoc[Position.RIGHT] = Location.NONE; location = newLoc; } for (int i = 0; i < location.length; i++) { if (location[i] == Location.NONE && i < gl.location.length) location[i] = gl.location[i]; } }
private void addRoughOffsetCurves(Collection offsetCurves, Geometry sourceCurve, BufferParameters parameters, Double offsetDistance) { OffsetCurveBuilder builder = new OffsetCurveBuilder( sourceCurve.getFactory().getPrecisionModel(), parameters); for (int i = 0; i < sourceCurve.getNumGeometries(); i++) { if (sourceCurve.getGeometryN(i) instanceof LineString) { LineString lineString = (LineString) sourceCurve.getGeometryN(i); Coordinate[] cc = lineString.getCoordinates(); if (lineString.isClosed()) { offsetCurves.add(lineString.getFactory().createLineString( builder.getRingCurve(cc, offsetDistance > 0 ? Position.LEFT : Position.RIGHT, Math.abs(offsetDistance)))); } else { offsetCurves.add(lineString.getFactory().createLineString( builder.getOffsetCurve(cc, offsetDistance))); } } } }
private void setInteriorEdgesInResult(PlanarGraph graph) { for (Object o : graph.getEdgeEnds()) { DirectedEdge de = (DirectedEdge) o; if (de.getLabel().getLocation(0, Position.RIGHT) == Location.INTERIOR) { de.setInResult(true); } } }
private boolean isPotentialResultAreaEdge(DirectedEdge de, int opCode) { // mark all dirEdges with the appropriate label Label label = de.getLabel(); return label.isArea() && !de.isInteriorAreaEdge() && OverlayOp.isResultOfOp( label.getLocation(0, Position.RIGHT), label.getLocation(1, Position.RIGHT), opCode); }
/** * Update the labels for edges according to their depths. * For each edge, the depths are first normalized. * Then, if the depths for the edge are equal, * this edge must have collapsed into a line edge. * If the depths are not equal, update the label * with the locations corresponding to the depths * (i.e. a depth of 0 corresponds to a Location of EXTERIOR, * a depth of 1 corresponds to INTERIOR) */ private void computeLabelsFromDepths() { for (Iterator it = this.edgeList.iterator(); it.hasNext(); ) { Edge e = (Edge) it.next(); Label lbl = e.getLabel(); Depth depth = e.getDepth(); /** * Only check edges for which there were duplicates, * since these are the only ones which might * be the result of dimensional collapses. */ if (!depth.isNull()) { depth.normalize(); for (int i = 0; i < 2; i++) { if (!lbl.isNull(i) && lbl.isArea() && !depth.isNull(i)) { /** * if the depths are equal, this edge is the result of * the dimensional collapse of two or more edges. * It has the same location on both sides of the edge, * so it has collapsed to a line. */ if (depth.getDelta(i) == 0) { lbl.toLine(i); } else { /** * This edge may be the result of a dimensional collapse, * but it still has different locations on both sides. The * label of the edge must be updated to reflect the resultant * side locations indicated by the depth values. */ Assert.isTrue(!depth.isNull(i, Position.LEFT), "depth of LEFT side has not been initialized"); lbl.setLocation(i, Position.LEFT, depth.getLocation(i, Position.LEFT)); Assert.isTrue(!depth.isNull(i, Position.RIGHT), "depth of RIGHT side has not been initialized"); lbl.setLocation(i, Position.RIGHT, depth.getLocation(i, Position.RIGHT)); } } } } } }
public void findEdge(List dirEdgeList) { /** * Check all forward DirectedEdges only. This is still general, * because each edge has a forward DirectedEdge. */ for (Object aDirEdgeList : dirEdgeList) { DirectedEdge de = (DirectedEdge) aDirEdgeList; if (!de.isForward()) { continue; } this.checkForRightmostCoordinate(de); } /** * If the rightmost point is a node, we need to identify which of * the incident edges is rightmost. */ Assert.isTrue(this.minIndex != 0 || this.minCoord.equals(this.minDe.getCoordinate()), "inconsistency in rightmost processing"); if (this.minIndex == 0) { this.findRightmostEdgeAtNode(); } else { this.findRightmostEdgeAtVertex(); } /** * now check that the extreme side is the R side. * If not, use the sym instead. */ this.orientedDe = this.minDe; int rightmostSide = this.getRightmostSide(this.minDe, this.minIndex); if (rightmostSide == Position.LEFT) { this.orientedDe = this.minDe.getSym(); } }
private void computeLineBufferCurve(Coordinate[] inputPts, OffsetSegmentGenerator segGen) { double distTol = simplifyTolerance(this.distance); //--------- compute points for left side of line // Simplify the appropriate side of the line before generating Coordinate[] simp1 = BufferInputLineSimplifier.simplify(inputPts, distTol); // MD - used for testing only (to eliminate simplification) // Coordinate[] simp1 = inputPts; int n1 = simp1.length - 1; segGen.initSideSegments(simp1[0], simp1[1], Position.LEFT); for (int i = 2; i <= n1; i++) { segGen.addNextSegment(simp1[i], true); } segGen.addLastSegment(); // add line cap for end of line segGen.addLineEndCap(simp1[n1 - 1], simp1[n1]); //---------- compute points for right side of line // Simplify the appropriate side of the line before generating Coordinate[] simp2 = BufferInputLineSimplifier.simplify(inputPts, -distTol); // MD - used for testing only (to eliminate simplification) // Coordinate[] simp2 = inputPts; int n2 = simp2.length - 1; // since we are traversing line in opposite order, offset position is still LEFT segGen.initSideSegments(simp2[n2], simp2[n2 - 1], Position.LEFT); for (int i = n2 - 2; i >= 0; i--) { segGen.addNextSegment(simp2[i], true); } segGen.addLastSegment(); // add line cap for start of line segGen.addLineEndCap(simp2[1], simp2[0]); segGen.closeRing(); }
private void computeSingleSidedBufferCurve(Coordinate[] inputPts, boolean isRightSide, OffsetSegmentGenerator segGen) { double distTol = simplifyTolerance(this.distance); if (isRightSide) { // add original line segGen.addSegments(inputPts, true); //---------- compute points for right side of line // Simplify the appropriate side of the line before generating Coordinate[] simp2 = BufferInputLineSimplifier.simplify(inputPts, -distTol); // MD - used for testing only (to eliminate simplification) // Coordinate[] simp2 = inputPts; int n2 = simp2.length - 1; // since we are traversing line in opposite order, offset position is still LEFT segGen.initSideSegments(simp2[n2], simp2[n2 - 1], Position.LEFT); segGen.addFirstSegment(); for (int i = n2 - 2; i >= 0; i--) { segGen.addNextSegment(simp2[i], true); } } else { // add original line segGen.addSegments(inputPts, false); //--------- compute points for left side of line // Simplify the appropriate side of the line before generating Coordinate[] simp1 = BufferInputLineSimplifier.simplify(inputPts, distTol); // MD - used for testing only (to eliminate simplification) // Coordinate[] simp1 = inputPts; int n1 = simp1.length - 1; segGen.initSideSegments(simp1[0], simp1[1], Position.LEFT); segGen.addFirstSegment(); for (int i = 2; i <= n1; i++) { segGen.addNextSegment(simp1[i], true); } } segGen.addLastSegment(); segGen.closeRing(); }
private void computeOffsetCurve(Coordinate[] inputPts, boolean isRightSide, OffsetSegmentGenerator segGen) { double distTol = simplifyTolerance(this.distance); if (isRightSide) { //---------- compute points for right side of line // Simplify the appropriate side of the line before generating Coordinate[] simp2 = BufferInputLineSimplifier.simplify(inputPts, -distTol); // MD - used for testing only (to eliminate simplification) // Coordinate[] simp2 = inputPts; int n2 = simp2.length - 1; // since we are traversing line in opposite order, offset position is still LEFT segGen.initSideSegments(simp2[n2], simp2[n2 - 1], Position.LEFT); segGen.addFirstSegment(); for (int i = n2 - 2; i >= 0; i--) { segGen.addNextSegment(simp2[i], true); } } else { //--------- compute points for left side of line // Simplify the appropriate side of the line before generating Coordinate[] simp1 = BufferInputLineSimplifier.simplify(inputPts, distTol); // MD - used for testing only (to eliminate simplification) // Coordinate[] simp1 = inputPts; int n1 = simp1.length - 1; segGen.initSideSegments(simp1[0], simp1[1], Position.LEFT); segGen.addFirstSegment(); for (int i = 2; i <= n1; i++) { segGen.addNextSegment(simp1[i], true); } } segGen.addLastSegment(); }
/** * Compute the change in depth as an edge is crossed from R to L */ private static int depthDelta(Label label) { int lLoc = label.getLocation(0, Position.LEFT); int rLoc = label.getLocation(0, Position.RIGHT); if (lLoc == Location.INTERIOR && rLoc == Location.EXTERIOR) { return 1; } else if (lLoc == Location.EXTERIOR && rLoc == Location.INTERIOR) { return -1; } return 0; }
public void computeDepth(int outsideDepth) { this.clearVisitedEdges(); // find an outside edge to assign depth to DirectedEdge de = this.finder.getEdge(); Node n = de.getNode(); Label label = de.getLabel(); // right side of line returned by finder is on the outside de.setEdgeDepths(Position.RIGHT, outsideDepth); this.copySymDepths(de); //computeNodeDepth(n, de); this.computeDepths(de); }
public void addNextSegment(Coordinate p, boolean addStartPoint) { // s0-s1-s2 are the coordinates of the previous segment and the current one this.s0 = this.s1; this.s1 = this.s2; this.s2 = p; this.seg0.setCoordinates(this.s0, this.s1); this.computeOffsetSegment(this.seg0, this.side, this.distance, this.offset0); this.seg1.setCoordinates(this.s1, this.s2); this.computeOffsetSegment(this.seg1, this.side, this.distance, this.offset1); // do nothing if points are equal if (this.s1.equals(this.s2)) { return; } int orientation = CGAlgorithms.computeOrientation(this.s0, this.s1, this.s2); boolean outsideTurn = (orientation == CGAlgorithms.CLOCKWISE && this.side == Position.LEFT) || (orientation == CGAlgorithms.COUNTERCLOCKWISE && this.side == Position.RIGHT); if (orientation == 0) { // lines are collinear this.addCollinear(addStartPoint); } else if (outsideTurn) { this.addOutsideTurn(orientation, addStartPoint); } else { // inside turn this.addInsideTurn(orientation, addStartPoint); } }
/** * Compute an offset segment for an input segment on a given side and at a given distance. * The offset points are computed in full double precision, for accuracy. * * @param seg the segment to offset * @param side the side of the segment ({@link Position}) the offset lies on * @param distance the offset distance * @param offset the points computed for the offset segment */ private void computeOffsetSegment(LineSegment seg, int side, double distance, LineSegment offset) { int sideSign = side == Position.LEFT ? 1 : -1; double dx = seg.p1.x - seg.p0.x; double dy = seg.p1.y - seg.p0.y; double len = Math.sqrt(dx * dx + dy * dy); // u is the vector that is the length of the offset, in the direction of the segment double ux = sideSign * distance * dx / len; double uy = sideSign * distance * dy / len; offset.p0.x = seg.p0.x - uy; offset.p0.y = seg.p0.y + ux; offset.p1.x = seg.p1.x - uy; offset.p1.y = seg.p1.y + ux; }
private void computeLineBufferCurve(Coordinate[] inputPts, OffsetSegmentGenerator segGen) { double distTol = simplifyTolerance(distance); //--------- compute points for left side of line // Simplify the appropriate side of the line before generating Coordinate[] simp1 = BufferInputLineSimplifier.simplify(inputPts, distTol); // MD - used for testing only (to eliminate simplification) // Coordinate[] simp1 = inputPts; int n1 = simp1.length - 1; segGen.initSideSegments(simp1[0], simp1[1], Position.LEFT); for (int i = 2; i <= n1; i++) { segGen.addNextSegment(simp1[i], true); } segGen.addLastSegment(); // add line cap for end of line segGen.addLineEndCap(simp1[n1 - 1], simp1[n1]); //---------- compute points for right side of line // Simplify the appropriate side of the line before generating Coordinate[] simp2 = BufferInputLineSimplifier.simplify(inputPts, -distTol); // MD - used for testing only (to eliminate simplification) // Coordinate[] simp2 = inputPts; int n2 = simp2.length - 1; // since we are traversing line in opposite order, offset position is still LEFT segGen.initSideSegments(simp2[n2], simp2[n2 - 1], Position.LEFT); for (int i = n2 - 2; i >= 0; i--) { segGen.addNextSegment(simp2[i], true); } segGen.addLastSegment(); // add line cap for start of line segGen.addLineEndCap(simp2[1], simp2[0]); segGen.closeRing(); }
private void computeSingleSidedBufferCurve(Coordinate[] inputPts, boolean isRightSide, OffsetSegmentGenerator segGen) { double distTol = simplifyTolerance(distance); if (isRightSide) { // add original line segGen.addSegments(inputPts, true); //---------- compute points for right side of line // Simplify the appropriate side of the line before generating Coordinate[] simp2 = BufferInputLineSimplifier.simplify(inputPts, -distTol); // MD - used for testing only (to eliminate simplification) // Coordinate[] simp2 = inputPts; int n2 = simp2.length - 1; // since we are traversing line in opposite order, offset position is still LEFT segGen.initSideSegments(simp2[n2], simp2[n2 - 1], Position.LEFT); segGen.addFirstSegment(); for (int i = n2 - 2; i >= 0; i--) { segGen.addNextSegment(simp2[i], true); } } else { // add original line segGen.addSegments(inputPts, false); //--------- compute points for left side of line // Simplify the appropriate side of the line before generating Coordinate[] simp1 = BufferInputLineSimplifier.simplify(inputPts, distTol); // MD - used for testing only (to eliminate simplification) // Coordinate[] simp1 = inputPts; int n1 = simp1.length - 1; segGen.initSideSegments(simp1[0], simp1[1], Position.LEFT); segGen.addFirstSegment(); for (int i = 2; i <= n1; i++) { segGen.addNextSegment(simp1[i], true); } } segGen.addLastSegment(); segGen.closeRing(); }
private void computeOffsetCurve(Coordinate[] inputPts, boolean isRightSide, OffsetSegmentGenerator segGen) { double distTol = simplifyTolerance(distance); if (isRightSide) { //---------- compute points for right side of line // Simplify the appropriate side of the line before generating Coordinate[] simp2 = BufferInputLineSimplifier.simplify(inputPts, -distTol); // MD - used for testing only (to eliminate simplification) // Coordinate[] simp2 = inputPts; int n2 = simp2.length - 1; // since we are traversing line in opposite order, offset position is still LEFT segGen.initSideSegments(simp2[n2], simp2[n2 - 1], Position.LEFT); segGen.addFirstSegment(); for (int i = n2 - 2; i >= 0; i--) { segGen.addNextSegment(simp2[i], true); } } else { //--------- compute points for left side of line // Simplify the appropriate side of the line before generating Coordinate[] simp1 = BufferInputLineSimplifier.simplify(inputPts, distTol); // MD - used for testing only (to eliminate simplification) // Coordinate[] simp1 = inputPts; int n1 = simp1.length - 1; segGen.initSideSegments(simp1[0], simp1[1], Position.LEFT); segGen.addFirstSegment(); for (int i = 2; i <= n1; i++) { segGen.addNextSegment(simp1[i], true); } } segGen.addLastSegment(); }
/** * Finds all non-horizontal segments intersecting the stabbing line * in the input dirEdge. * The stabbing line is the ray to the right of stabbingRayLeftPt. * * @param stabbingRayLeftPt the left-hand origin of the stabbing line * @param stabbedSegments the current list of {@link DepthSegments} intersecting the stabbing line */ private void findStabbedSegments(Coordinate stabbingRayLeftPt, DirectedEdge dirEdge, List stabbedSegments) { Coordinate[] pts = dirEdge.getEdge().getCoordinates(); for (int i = 0; i < pts.length - 1; i++) { seg.p0 = pts[i]; seg.p1 = pts[i + 1]; // ensure segment always points upwards if (seg.p0.y > seg.p1.y) seg.reverse(); // skip segment if it is left of the stabbing line double maxx = Math.max(seg.p0.x, seg.p1.x); if (maxx < stabbingRayLeftPt.x) continue; // skip horizontal segments (there will be a non-horizontal one carrying the same depth info if (seg.isHorizontal()) continue; // skip if segment is above or below stabbing line if (stabbingRayLeftPt.y < seg.p0.y || stabbingRayLeftPt.y > seg.p1.y) continue; // skip if stabbing ray is right of the segment if (CGAlgorithms.computeOrientation(seg.p0, seg.p1, stabbingRayLeftPt) == CGAlgorithms.RIGHT) continue; // stabbing line cuts this segment, so record it int depth = dirEdge.getDepth(Position.LEFT); // if segment direction was flipped, use RHS depth instead if (!seg.p0.equals(pts[i])) depth = dirEdge.getDepth(Position.RIGHT); DepthSegment ds = new DepthSegment(seg, depth); stabbedSegments.add(ds); } }
public void flip() { if (location.length <= 1) return; int temp = location[Position.LEFT]; location[Position.LEFT] = location[Position.RIGHT]; location[Position.RIGHT] = temp; }
public String toString() { StringBuffer buf = new StringBuffer(); if (location.length > 1) buf.append(Location.toLocationSymbol(location[Position.LEFT])); buf.append(Location.toLocationSymbol(location[Position.ON])); if (location.length > 1) buf.append(Location.toLocationSymbol(location[Position.RIGHT])); return buf.toString(); }