private List <PointDouble> ClipToBounds(Rectangle bounds) { var points = new List <PointDouble>(); int n = _edges.Count; int i = 0; Edge edge; while (i < n && (!_edges[i].IsVisible)) { ++i; } if (i == n) { // no edges visible return(new List <PointDouble>()); } edge = _edges[i]; LR orientation = _edgeOrientations[i]; points.Add(edge.ClippedEnds[orientation]); points.Add(edge.ClippedEnds[orientation.other()]); for (int j = i + 1; j < n; ++j) { edge = _edges[j]; if (!edge.IsVisible) { continue; } Connect(points, j, bounds, false); } // close up the polygon by adding another corner point of the bounds if needed: Connect(points, i, bounds, true); return(points); }
private void Connect(List <PointDouble> points, int j, Rectangle bounds, bool closingUp) { PointDouble rightPoint = points[points.Count - 1]; Edge newEdge = _edges[j]; LR newOrientation = _edgeOrientations[j]; // the point that must be connected to rightPoint: PointDouble newPoint = newEdge.ClippedEnds[newOrientation]; if (!CloseEnough(rightPoint, newPoint)) { // The points do not coincide, so they must have been clipped at the bounds; // see if they are on the same border of the bounds: if (rightPoint.X != newPoint.X && rightPoint.Y != newPoint.Y) { // They are on different borders of the bounds; // insert one or two corners of bounds as needed to hook them up: // (NOTE this will not be correct if the region should take up more than // half of the bounds rect, for then we will have gone the wrong way // around the bounds and included the smaller part rather than the larger) int rightCheck = BoundsCheck.Check(rightPoint, bounds); int newCheck = BoundsCheck.Check(newPoint, bounds); double px, py; if ((rightCheck & BoundsCheck.RIGHT) != 0) { px = bounds.right; if ((newCheck & BoundsCheck.BOTTOM) != 0) { py = bounds.bottom; points.Add(new PointDouble(px, py)); } else if ((newCheck & BoundsCheck.TOP) != 0) { py = bounds.top; points.Add(new PointDouble(px, py)); } else if ((newCheck & BoundsCheck.LEFT) != 0) { if (rightPoint.Y - bounds.y + newPoint.Y - bounds.y < bounds.height) { py = bounds.top; } else { py = bounds.bottom; } points.Add(new PointDouble(px, py)); points.Add(new PointDouble(bounds.left, py)); } } else if ((rightCheck & BoundsCheck.LEFT) != 0) { px = bounds.left; if ((newCheck & BoundsCheck.BOTTOM) != 0) { py = bounds.bottom; points.Add(new PointDouble(px, py)); } else if ((newCheck & BoundsCheck.TOP) != 0) { py = bounds.top; points.Add(new PointDouble(px, py)); } else if ((newCheck & BoundsCheck.RIGHT) != 0) { if (rightPoint.Y - bounds.y + newPoint.Y - bounds.y < bounds.height) { py = bounds.top; } else { py = bounds.bottom; } points.Add(new PointDouble(px, py)); points.Add(new PointDouble(bounds.right, py)); } } else if ((rightCheck & BoundsCheck.TOP) != 0) { py = bounds.top; if ((newCheck & BoundsCheck.RIGHT) != 0) { px = bounds.right; points.Add(new PointDouble(px, py)); } else if ((newCheck & BoundsCheck.LEFT) != 0) { px = bounds.left; points.Add(new PointDouble(px, py)); } else if ((newCheck & BoundsCheck.BOTTOM) != 0) { if (rightPoint.X - bounds.x + newPoint.X - bounds.x < bounds.width) { px = bounds.left; } else { px = bounds.right; } points.Add(new PointDouble(px, py)); points.Add(new PointDouble(px, bounds.bottom)); } } else if ((rightCheck & BoundsCheck.BOTTOM) != 0) { py = bounds.bottom; if ((newCheck & BoundsCheck.RIGHT) != 0) { px = bounds.right; points.Add(new PointDouble(px, py)); } else if ((newCheck & BoundsCheck.LEFT) != 0) { px = bounds.left; points.Add(new PointDouble(px, py)); } else if ((newCheck & BoundsCheck.TOP) != 0) { if (rightPoint.X - bounds.x + newPoint.X - bounds.x < bounds.width) { px = bounds.left; } else { px = bounds.right; } points.Add(new PointDouble(px, py)); points.Add(new PointDouble(px, bounds.top)); } } } if (closingUp) { // newEdge's ends have already been added return; } points.Add(newPoint); } var newRightPoint = newEdge.ClippedEnds[newOrientation.other()]; if (!CloseEnough(points[0], newRightPoint)) { points.Add(newRightPoint); } }