internal BorderPath ComputeGraphicsPath(Sector sector, PathUtil.PathType type) { lock (this) { if (borderPathsCache[(int)type] == null) { borderPathsCache[(int)type] = new BorderPath(this, sector, type); } } return(borderPathsCache[(int)type]); }
internal ClipPath ComputeClipPath(PathUtil.PathType type) { lock (this) { if (clipPathsCache[(int)type] == null) { clipPathsCache[(int)type] = new ClipPath(this, type); } } return(clipPathsCache[(int)type]); }
public ClipPath(Sector sector, PathUtil.PathType borderPathType) { float[] edgex, edgey; RenderUtil.HexEdges(borderPathType, out edgex, out edgey); Rectangle bounds = sector.Bounds; List <Point> clip = new List <Point>(); clip.AddRange(Util.Sequence(1, Astrometrics.SectorWidth).Select(x => new Point(x, 1))); clip.AddRange(Util.Sequence(2, Astrometrics.SectorHeight).Select(y => new Point(Astrometrics.SectorWidth, y))); clip.AddRange(Util.Sequence(Astrometrics.SectorWidth - 1, 1).Select(x => new Point(x, Astrometrics.SectorHeight))); clip.AddRange(Util.Sequence(Astrometrics.SectorHeight - 1, 1).Select(y => new Point(1, y))); for (int i = 0; i < clip.Count; ++i) { Point pt = clip[i]; pt.Offset(bounds.Location); clip[i] = pt; } PathUtil.ComputeBorderPath(clip, edgex, edgey, out clipPathPoints, out clipPathPointTypes); PointF min = clipPathPoints[0]; PointF max = clipPathPoints[0]; for (int i = 1; i < clipPathPoints.Length; ++i) { PointF pt = clipPathPoints[i]; if (pt.X < min.X) { min.X = pt.X; } if (pt.Y < min.Y) { min.Y = pt.Y; } if (pt.X > max.X) { max.X = pt.X; } if (pt.Y > max.Y) { max.Y = pt.Y; } } this.bounds = new RectangleF(min, new SizeF(max.X - min.X, max.Y - min.Y)); }
public ClipPath(Sector sector, PathUtil.PathType borderPathType) { float[] edgex, edgey; RenderUtil.HexEdges(borderPathType, out edgex, out edgey); IEnumerable <Hex> hexes = Util.Sequence(1, Astrometrics.SectorWidth).Select(x => new Hex((byte)x, 1)) .Concat(Util.Sequence(2, Astrometrics.SectorHeight).Select(y => new Hex(Astrometrics.SectorWidth, (byte)y))) .Concat(Util.Sequence(Astrometrics.SectorWidth - 1, 1).Select(x => new Hex((byte)x, Astrometrics.SectorHeight))) .Concat(Util.Sequence(Astrometrics.SectorHeight - 1, 1).Select(y => new Hex(1, (byte)y))); Rectangle bounds = sector.Bounds; IEnumerable <Point> points = (from hex in hexes select new Point(hex.X + bounds.X, hex.Y + bounds.Y)).ToList(); PathUtil.ComputeBorderPath(points, edgex, edgey, out clipPathPoints, out clipPathPointTypes); PointF min = clipPathPoints[0]; PointF max = clipPathPoints[0]; for (int i = 1; i < clipPathPoints.Length; ++i) { PointF pt = clipPathPoints[i]; if (pt.X < min.X) { min.X = pt.X; } if (pt.Y < min.Y) { min.Y = pt.Y; } if (pt.X > max.X) { max.X = pt.X; } if (pt.Y > max.Y) { max.Y = pt.Y; } } this.bounds = new RectangleF(min, new SizeF(max.X - min.X, max.Y - min.Y)); }
public BorderPath(Border border, Sector sector, PathUtil.PathType type) { RenderUtil.HexEdges(type, out float[] edgeX, out float[] edgeY); int lengthEstimate = border.Path.Count() * 3; List <PointF> points = new List <PointF>(lengthEstimate); List <byte> types = new List <byte>(lengthEstimate); LinkedList <LinkedList <PointF> > segments = new LinkedList <LinkedList <PointF> >(); LinkedList <PointF> currentSegment = new LinkedList <PointF>(); // Based on http://dotclue.org/t20/sec2pdf - J Greely rocks my world. int checkFirst = 0; int checkLast = 5; Hex startHex = Hex.Empty; bool startHexVisited = false; foreach (Hex hex in border.Path) { checkLast = checkFirst + 5; if (startHexVisited && hex == startHex) { // I'm in the starting hex, and I've been // there before, so stop testing at neighbor // 5, no matter what checkLast = 5; // degenerate case, entering for third time if (checkFirst < 3) { break; } } else if (!startHexVisited) { startHex = hex; startHexVisited = true; // PERF: This seems costly... analyze it! PointF newPoint = Astrometrics.HexToCenter(Astrometrics.LocationToCoordinates(new Location(sector.Location, hex))); newPoint.X += edgeX[0]; newPoint.Y += edgeY[0]; // MOVETO points.Add(newPoint); types.Add((byte)PathPointType.Start); // MOVETO currentSegment.AddLast(newPoint); } PointF pt = Astrometrics.HexToCenter(Astrometrics.LocationToCoordinates(new Location(sector.Location, hex))); int i = checkFirst; for (int check = checkFirst; check <= checkLast; check++) { i = check; Hex neighbor = Astrometrics.HexNeighbor(hex, i % 6); if (border.Path.Contains(neighbor)) // TODO: Consider a hash here { break; } PointF newPoint = new PointF(pt.X + edgeX[(i + 1) % 6], pt.Y + edgeY[(i + 1) % 6]); // LINETO points.Add(newPoint); types.Add((byte)PathPointType.Line); if (hex.IsValid) { // MOVETO currentSegment.AddLast(newPoint); } else { // LINETO if (currentSegment.Count > 1) { segments.AddLast(currentSegment); } currentSegment = new LinkedList <PointF>(); currentSegment.AddLast(newPoint); } } i %= 6; // i is the direction to the next border hex, // and when we get there, we'll have come from // i + 3, so we start checking with i + 4. checkFirst = (i + 4) % 6; } if (points.First() == points.Last()) { int c = points.Count; points.RemoveAt(c - 1); types.RemoveAt(c - 1); } types[types.Count - 1] |= (byte)PathPointType.CloseSubpath; if (currentSegment.Count > 1) { segments.AddLast(currentSegment); } this.points = points.ToArray(); this.types = types.ToArray(); // If last curve segment connects to first curve segment, merge them. // Example: Imperial border in Verge. if (segments.Count >= 2 && segments.First().First() == segments.Last().Last()) { var first = segments.First(); var last = segments.Last(); segments.RemoveFirst(); first.RemoveFirst(); foreach (var point in first) { last.AddLast(point); } } curves = segments.Select(c => { if (c.First() == c.Last()) { c.RemoveLast(); return(new CurveSegment(c, true)); } else { return(new CurveSegment(c, false)); } }).ToList(); }
public static void HexEdges(PathUtil.PathType type, out float[] edgeX, out float[] edgeY) { edgeX = (type == PathUtil.PathType.Hex) ? RenderUtil.HexEdgesX : RenderUtil.SquareEdgesX; edgeY = (type == PathUtil.PathType.Hex) ? RenderUtil.HexEdgesY : RenderUtil.SquareEdgesY; }
public BorderPath(Border border, Sector sector, PathUtil.PathType type) { float[] edgeX, edgeY; RenderUtil.HexEdges(type, out edgeX, out edgeY); int lengthEstimate = border.Path.Length * 3; List <PointF> borderPathPoints = new List <PointF>(lengthEstimate); List <byte> borderPathTypes = new List <byte>(lengthEstimate); List <PointF> clipPathPoints = new List <PointF>(lengthEstimate); List <byte> clipPathTypes = new List <byte>(lengthEstimate); List <List <PointF> > curves = new List <List <PointF> >(lengthEstimate); List <PointF> curve = new List <PointF>(lengthEstimate); // Based on http://dotclue.org/t20/sec2pdf - J Greely rocks my world. int checkFirst = 0; int checkLast = 5; int startHex = 0; bool startHexVisited = false; foreach (int hex in border.Path) { checkLast = checkFirst + 5; if (startHexVisited && hex == startHex) { // I'm in the starting hex, and I've been // there before, so stop testing at neighbor // 5, no matter what checkLast = 5; // degenerate case, entering for third time if (checkFirst < 3) { break; } } else if (!startHexVisited) { startHex = hex; startHexVisited = true; // PERF: This seems costly... analyze it! PointF newPoint = Astrometrics.HexToCenter(Astrometrics.LocationToCoordinates(new Location(sector.Location, hex))); newPoint.X += edgeX[0]; newPoint.Y += edgeY[0]; // MOVETO borderPathPoints.Add(newPoint); borderPathTypes.Add((byte)PathPointType.Start); // MOVETO clipPathPoints.Add(newPoint); clipPathTypes.Add((byte)PathPointType.Start); if (curve.Count > 1) { curves.Add(curve); curve = new List <PointF>(lengthEstimate); curve.Add(newPoint); } else { curve.Clear(); curve.Add(newPoint); } } PointF pt = Astrometrics.HexToCenter(Astrometrics.LocationToCoordinates(new Location(sector.Location, hex))); int i = checkFirst; for (int check = checkFirst; check <= checkLast; check++) { i = check; int neighbor = Astrometrics.HexNeighbor(hex, i % 6); if (Array.IndexOf <int>(border.Path, neighbor) != -1) // Consider a hash here { break; } PointF newPoint = new PointF(pt.X + edgeX[(i + 1) % 6], pt.Y + edgeY[(i + 1) % 6]); // TODO: Replace this by clipping borders to sector bounds; problem - bottom/right edges protrude // Only actually render edges within the sector //if( 1 <= ( hex / 100 ) && ( hex / 100 ) <= 32 && 1 <= ( hex % 100 ) && ( hex % 100 ) <= 40 ) { // LINETO borderPathPoints.Add(newPoint); borderPathTypes.Add((byte)PathPointType.Line); //curve.Add( newPoint ); if (Util.InRange(hex / 100, 1, Astrometrics.SectorWidth) && Util.InRange(hex % 100, 1, Astrometrics.SectorHeight)) { curve.Add(newPoint); } else { if (curve.Count > 1) { curves.Add(curve); curve = new List <PointF>(lengthEstimate); curve.Add(newPoint); } else { curve.Clear(); curve.Add(newPoint); } } } /* * else * { * // MOVETO * if( borderPathTypes[ borderPathTypes.Count - 1 ] == (byte)PathPointType.Start ) * { * // Collapse multiple MOVETOs - makes GDI+ happy * borderPathPoints[ borderPathPoints.Count - 1 ] = newPoint; * } * else * { * borderPathPoints.Add( newPoint ); * borderPathTypes.Add( (byte)PathPointType.Start ); * } * * if( curve.Count > 1 ) * { * curves.Add( curve ); * curve = new List<PointF>( lengthEstimate ); * curve.Add( newPoint ); * } * else * { * curve.Clear(); * curve.Add( newPoint ); * } * } * */ // LINETO clipPathPoints.Add(newPoint); clipPathTypes.Add((byte)PathPointType.Line); } i = i % 6; // i is the direction to the next border hex, // and when we get there, we'll have come from // i + 3, so we start checking with i + 4. checkFirst = (i + 4) % 6; } // Trim trailing MOVETOs - makes GDI+ happy while (borderPathTypes.Count > 0 && borderPathTypes[borderPathTypes.Count - 1] == (byte)PathPointType.Start) { borderPathTypes.RemoveAt(borderPathTypes.Count - 1); borderPathPoints.RemoveAt(borderPathPoints.Count - 1); } borderPathTypes[borderPathTypes.Count - 1] |= (byte)PathPointType.CloseSubpath; this.borderPathPoints = borderPathPoints.ToArray(); this.borderPathTypes = borderPathTypes.ToArray(); this.clipPathPoints = clipPathPoints.ToArray(); this.clipPathTypes = clipPathTypes.ToArray(); if (curve.Count > 1) { curves.Add(curve); } this.curvePoints = curves.Select(c => c.ToArray()).ToArray(); }