public static void DrawComponents(Data.Layer layer, CanvasDrawingSession ds, float rescale, Color componentColor, bool drawSelection = false) { var margin = 4 * rescale; var originColor = Color.FromArgb(135, 34, 34, 34); var selectedComponentColor = Color.FromArgb( 135, (byte)Math.Max(componentColor.R - 90, 0), (byte)Math.Max(componentColor.G - 90, 0), (byte)Math.Max(componentColor.B - 90, 0) ); foreach (var component in layer.Components) { ds.FillGeometry(component.ClosedCanvasPath, drawSelection && component.IsSelected ? selectedComponentColor : componentColor); ds.DrawGeometry(component.OpenCanvasPath, componentColor, strokeWidth: rescale); if (drawSelection && component.IsSelected) { var origin = component.Origin; ds.DrawLine(origin.X, origin.Y + margin, origin.X, origin.Y - margin, originColor, strokeWidth: rescale); ds.DrawLine(origin.X - margin, origin.Y, origin.X + margin, origin.Y, originColor, strokeWidth: rescale); } } }
public static void MoveSelection(Data.Layer layer, float dx, float dy, MoveMode mode = MoveMode.Normal) { using var group = layer.CreateUndoGroup(); foreach (var anchor in layer.Anchors) { if (anchor.IsSelected) { anchor.X = RoundToGrid(anchor.X + dx); anchor.Y = RoundToGrid(anchor.Y + dy); } } foreach (var component in layer.Components) { if (component.IsSelected) { var t = component.Transformation; t.M31 = RoundToGrid(t.M31 + dx); t.M32 = RoundToGrid(t.M32 + dy); component.Transformation = t; } } foreach (var guideline in UIBroker.GetAllGuidelines(layer)) { if (guideline.IsSelected) { guideline.X = RoundToGrid(guideline.X + dx); guideline.Y = RoundToGrid(guideline.Y + dy); } } foreach (var path in layer.Paths) { MoveSelection(path, dx, dy, mode); } }
/// <summary> /// Create standard geojson feature list from Line objects /// </summary> /// <param name="Lines"></param> /// <returns></returns> public List <Feature> ToGISGeojsonFeatures(List <Data.Line> Lines, Data.Layer Layer) { List <GIS.Feature> features = new List <GIS.Feature>(); foreach (var dbLine in Lines) { features.Add(new GIS.Feature("Feature") { friendlyname = Layer.LayerName, guid = Layer.LayerGuId, geometry = new GIS.LineStringGeometry("LineString") { coordinates = new decimal[][] { new decimal[] { dbLine.ALatitude, dbLine.ALongitude }, new decimal[] { dbLine.BLatitude, dbLine.BLongitude } } }, properties = new Properties() { oID = dbLine.LineId, color = dbLine.Color, opacity = dbLine.Opacity, weight = dbLine.Weight, fill = dbLine.Fill, fillColor = dbLine.FillColor, fillOpacity = dbLine.FillOpacity, descr1 = dbLine.Description1, descr2 = dbLine.Description2, descr3 = dbLine.Description3, } }); } return(features); }
public string SetDataTableName(Data.Layer Layer) { if (!string.IsNullOrEmpty(Layer.TableName)) { return(Layer.TableName); } else { if (Layer.LayerType == "point") { return(_AppConfig.DefaultPointTable); } else if (Layer.LayerType == "line") { return(_AppConfig.DefaultLineTable); } else if (Layer.LayerType == "geojson") { return(_AppConfig.DefaultGeojsonTable); } else { return(""); } } }
public static void StretchCurve(Data.Layer layer, IList <Data.Point> curve, float dx, float dy, bool maintainDirection = false) { Debug.Assert(curve.Count == 4); var leftVector = curve[1].ToVector2(); var rightVector = curve[2].ToVector2(); using var group = layer.CreateUndoGroup(); curve[1].X = curve[1].X + dx; curve[1].Y = curve[1].Y + dy; if (maintainDirection || curve[0].IsSmooth) { VectorProjection(curve[1], curve[0].ToVector2(), leftVector); } else { curve[1].X = RoundToGrid(curve[1].X); curve[1].Y = RoundToGrid(curve[1].Y); } curve[2].X = curve[2].X + dx; curve[2].Y = curve[2].Y + dy; if (maintainDirection || curve[3].IsSmooth) { VectorProjection(curve[2], curve[3].ToVector2(), rightVector); } else { curve[2].X = RoundToGrid(curve[2].X); curve[2].Y = RoundToGrid(curve[2].Y); } }
/// <summary> /// Create standard geojson feature list from Point objects /// </summary> /// <param name="Points"></param> /// <returns></returns> public List <Feature> ToGISGeojsonFeatures(List <Data.Point> Points, Data.Layer Layer) { List <GIS.Feature> features = new List <GIS.Feature>(); foreach (var dbPoint in Points) { features.Add(new GIS.Feature("Feature") { friendlyname = Layer.LayerName, guid = Layer.LayerGuId, geometry = new GIS.PointGeometry("Point") { coordinates = new decimal[] { dbPoint.Latitude, dbPoint.Longitude } }, properties = new GIS.Properties() { oID = dbPoint.PointID, color = dbPoint.Color, opacity = dbPoint.Opacity, weight = dbPoint.Weight, fill = dbPoint.Fill, fillColor = dbPoint.FillColor, fillOpacity = dbPoint.FillOpacity, descr1 = dbPoint.Descr1, descr2 = dbPoint.Descr2, descr3 = dbPoint.Descr3, radius = dbPoint.Radius, icon = dbPoint.Icon } }); } return(features); }
public static IEnumerable <BBoxHandle> GetSelectionHandles(Data.Layer layer, float rescale) { var bounds = layer.SelectionBounds; if (bounds.Width > 0 && bounds.Height > 0) { yield return(GetSelectionHandle(bounds, HandleKind.BottomLeft, rescale)); yield return(GetSelectionHandle(bounds, HandleKind.TopLeft, rescale)); yield return(GetSelectionHandle(bounds, HandleKind.TopRight, rescale)); yield return(GetSelectionHandle(bounds, HandleKind.BottomRight, rescale)); } if (bounds.Width > 0) { yield return(GetSelectionHandle(bounds, HandleKind.Left, rescale)); yield return(GetSelectionHandle(bounds, HandleKind.Right, rescale)); } if (bounds.Height > 0) { yield return(GetSelectionHandle(bounds, HandleKind.Bottom, rescale)); yield return(GetSelectionHandle(bounds, HandleKind.Top, rescale)); } }
void AlignPaths(Data.Layer layer, Func <Data.Path, Rect, Vector2> transformFunc) { Rect targetBounds; IEnumerable <Data.Path> targetPaths; bool alignToMetricsRect; if (layer.Selection.OfType <Data.Point>().Any()) { var selectedBounds = Rect.Empty; var selectedPaths = new List <Data.Path>(); foreach (var path in layer.Paths) { if (Enumerable.Any(path.Points, point => point.IsSelected)) { selectedBounds.Union(path.Bounds); selectedPaths.Add(path); } } targetBounds = selectedBounds; targetPaths = selectedPaths; alignToMetricsRect = selectedPaths.Count == 1; } else { targetBounds = default; // this just to appease the compiler.. targetPaths = layer.Paths; alignToMetricsRect = true; } if (alignToMetricsRect) { targetBounds = new Rect(0, 0, layer.Width, 0); if (layer.Master is Data.Master master) { targetBounds.Y = master.Descender; targetBounds.Height = Math.Max(master.Ascender, master.CapHeight) - targetBounds.Y; } } using (var group = layer.CreateUndoGroup()) { foreach (var path in targetPaths) { var delta = transformFunc(path, targetBounds); if (delta != Vector2.Zero) { path.Transform(Matrix3x2.CreateTranslation(delta)); } } } }
public static bool TryJoinPath(Data.Layer layer, Data.Point point) { if (Is.AtOpenBoundary(point) && layer.Paths .SelectMany(path => path.Points) .Where(p => p != point && p.X == point.X && p.Y == point.Y) .LastOrDefault() is Data.Point otherPoint) { return(TryJoinPath(layer, point, otherPoint)); } return(false); }
IList <Vector2> GetPointsWithEndpoints(Data.Layer layer, bool addIntersections = true) { var origin = _origin.Value.ToVector2(); var anchor = _anchor.ToVector2(); return(addIntersections switch { true => Enumerable.Concat(Slicing.IntersectPaths(layer, origin, anchor), new Vector2[] { origin, anchor }) .OrderBy(point => (point - origin).LengthSquared()) .ToArray(), false => new Vector2[] { origin, anchor } });
public static bool TryJoinPath(Data.Layer layer, Data.Point point, Data.Point otherPoint) { if (Is.AtOpenBoundary(point) && Is.AtOpenBoundary(otherPoint)) { JoinPaths(point.Parent, point.Parent.Points.IndexOf(point) == 0, otherPoint.Parent, otherPoint.Parent.Points.IndexOf(otherPoint) == 0, true); return(true); } return(false); }
public static void DeleteSelection(Data.Layer layer, bool breakPaths = false) { using var group = layer.CreateUndoGroup(); for (int ix = layer.Anchors.Count - 1; ix >= 0; --ix) { var anchor = layer.Anchors[ix]; if (anchor.IsSelected) { layer.Anchors.RemoveAt(ix); } } for (int ix = layer.Components.Count - 1; ix >= 0; --ix) { var component = layer.Components[ix]; if (component.IsSelected) { layer.Components.RemoveAt(ix); } } if (layer.Master is Data.Master master) { for (int ix = master.Guidelines.Count - 1; ix >= 0; --ix) { var guideline = master.Guidelines[ix]; if (guideline.IsSelected) { master.Guidelines.RemoveAt(ix); } } } for (int ix = layer.Guidelines.Count - 1; ix >= 0; --ix) { var guideline = layer.Guidelines[ix]; if (guideline.IsSelected) { layer.Guidelines.RemoveAt(ix); } } if (breakPaths) { BreakPathsSelection(layer); } else { DeletePathsSelection(layer); } }
public static void DrawCoordinates(Data.Layer layer, CanvasDrawingSession ds, float rescale) { var color = Color.FromArgb(255, 21, 116, 212); var canvasPath = layer.ClosedCanvasPath; var margin = 8 * rescale; foreach (var path in layer.Paths) { foreach (var(point, angle) in UIBroker.GetCurvePointsPreferredAngle(path)) { var pos = point.ToVector2() + margin * Conversion.ToVector(angle); CanvasHorizontalAlignment hAlignment; if (PI_5_8 <= angle && angle < PI_11_8) { hAlignment = CanvasHorizontalAlignment.Right; } // No && condition here, because we check around 0 or around 360 deg else if (angle < PI_3_8 || PI_13_8 <= angle) { hAlignment = CanvasHorizontalAlignment.Left; } else { hAlignment = CanvasHorizontalAlignment.Center; } float?baseline; CanvasVerticalAlignment vAlignment; if (PI_1_8 <= angle && angle < PI_7_8) { baseline = null; vAlignment = CanvasVerticalAlignment.Bottom; } else if (PI_9_8 <= angle && angle < PI_15_8) { baseline = .78f; vAlignment = CanvasVerticalAlignment.Top; } else { baseline = .93f; vAlignment = CanvasVerticalAlignment.Center; } var rx = MathF.Round(point.X, 1); var ry = MathF.Round(point.Y, 1); DrawText(ds, $"{rx}, {ry}", pos, color, fontSize: 10, hAlignment: hAlignment, vAlignment: vAlignment, baseline: baseline, rescale: rescale); } } }
public static void DrawGrid(Data.Layer layer, CanvasDrawingSession ds, float rescale, Data.Geometry.Rect drawingRect) { /*var color = Color.FromArgb(255, 220, 220, 220); * var gridSize = 1; * * for (int i = gridSize * (int)(bottomLeft.X / gridSize); i <= topRight.X; i += gridSize) * { * ds.DrawLine(i, (float)topRight.Y, i, (float)bottomLeft.Y, color, strokeWidth: rescale); * } * for (int i = gridSize * (int)(bottomLeft.Y / gridSize); i <= topRight.Y; i += gridSize) * { * ds.DrawLine((float)bottomLeft.X, i, (float)topRight.X, i, color, strokeWidth: rescale); * }*/ }
public static Vector2[] IntersectPaths(Data.Layer layer, Vector2 p0, Vector2 p1) { var points = new List <Vector2>(); foreach (var path in layer.Paths) { foreach (var segment in path.Segments) { foreach (var loc in segment.IntersectLine(p0, p1)) { points.Add(loc.Item1); } } } return(points.ToArray()); }
public static void RoundSelection(Data.Layer layer) { using var group = layer.CreateUndoGroup(); foreach (var anchor in layer.Anchors) { if (anchor.IsSelected) { anchor.X = RoundToGrid(anchor.X); anchor.Y = RoundToGrid(anchor.Y); } } foreach (var component in layer.Components) { if (component.IsSelected) { var t = component.Transformation; // TODO: could round scale to 2 decimal digits, like we do when transforming // worth having a round to digits (default = 2) method here? t.M31 = RoundToGrid(t.M31); t.M32 = RoundToGrid(t.M32); component.Transformation = t; } } foreach (var guideline in UIBroker.GetAllGuidelines(layer)) { if (guideline.IsSelected) { // TODO: introduce some angle rounding? guideline.X = RoundToGrid(guideline.X); guideline.Y = RoundToGrid(guideline.Y); } } foreach (var path in layer.Paths) { foreach (var point in path.Points) { if (point.IsSelected) { point.X = RoundToGrid(point.X); point.Y = RoundToGrid(point.Y); } } } }
public static void DrawAnchors(Data.Layer layer, CanvasDrawingSession ds, float rescale, Color color) { var size = 9 * rescale; var selectedSize = 11 * rescale; var margin = new Vector2( selectedSize, rescale ); foreach (var anchor in layer.Anchors) { using (var geometry = CreateLozenge(ds, anchor.X, anchor.Y, anchor.IsSelected ? selectedSize : size)) { ds.FillGeometry(geometry, color); } if (anchor.IsSelected && !string.IsNullOrEmpty(anchor.Name)) { DrawText(ds, anchor.Name, anchor.ToVector2() + margin, Colors.White, rescale: rescale, hAlignment: CanvasHorizontalAlignment.Left, vAlignment: CanvasVerticalAlignment.Center, backplateColor: Color.FromArgb(135, 45, 45, 45)); } } }
/// <summary> /// Create standard geojson feature list from Raw geojson features(not like database structured) /// </summary> /// <param name="RawGeoJson"></param> /// <returns></returns> public List <Feature> ToGISGeojsonFeatures(Data.DBGeojsonObject RawGeoJson, Data.Layer Layer) { List <Feature> features = new List <Feature>(); string JsonString = GeoJsonObjectToString(RawGeoJson); var parsed = Newtonsoft.Json.Linq.JObject.Parse(JsonString); JArray Val = (JArray)parsed["features"]; if (Val != null) { foreach (JToken jfeature in Val) { Feature geoFeature = new Feature(); geoFeature.friendlyname = Layer.LayerName; geoFeature.guid = Layer.LayerGuId; geoFeature.type = "Feature"; var featureGeometry = jfeature["geometry"]; var featureProperties = jfeature["properties"]; var geometryType = featureGeometry["type"]; var coordinates = featureGeometry["coordinates"]; //Properties geojsonProperties = (Properties)GetProperties(featureProperties); geoFeature.properties = GetProperties(featureProperties); geoFeature.properties.oID = RawGeoJson.oID; if ((string)geometryType == "Point") { var lat = (decimal)coordinates.Values().ElementAt(0); var lon = (decimal)coordinates.Values().ElementAt(1); geoFeature.geometry = new PointGeometry("Point") { coordinates = new[] { lat, lon } }; features.Add(geoFeature); } else if ((string)geometryType == "LineString") { int coordCount = coordinates.Count(); decimal[][] lineStringCoordinates = new decimal[coordCount][]; for (int i = 0; i < coordCount; i++) { var lat = (decimal)coordinates[i].Values().ElementAt(0); var lon = (decimal)coordinates[i].Values().ElementAt(1); lineStringCoordinates[i] = new decimal[] { lat, lon }; } geoFeature.geometry = new LineStringGeometry("LineString") { coordinates = lineStringCoordinates }; features.Add(geoFeature); } else if ((string)geometryType == "Polygon") { var polygonCoordinates = coordinates.First ?? ""; int coordCount = polygonCoordinates.Count(); decimal[][] polyFeatureCoordinates = new decimal[coordCount][]; for (int i = 0; i < coordCount; i++) { var lat = (decimal)polygonCoordinates[i].Values().ElementAt(0); var lon = (decimal)polygonCoordinates[i].Values().ElementAt(1); polyFeatureCoordinates[i] = new decimal[] { lat, lon }; } // donut polygon capability is unimplemented geoFeature.geometry = new PolygonGeometry("Polygon") { coordinates = new decimal[][][] { polyFeatureCoordinates } }; features.Add(geoFeature); } else if ((string)geometryType == "MultiPolygon") { //var polygonCoordinates = coordinates.First ?? ""; //int polygonCount = polygonCoordinates.Count(); //for (int i = 0; i < polygonCount; i++) //{ // var smallPolygon = polygonCoordinates[i].Values(); // int smallCount = smallPolygon.Count(); // decimal[][] polyFeatureCoordinates = new decimal[polygonCount][]; // for (int j = 0; j < smallCount; j++) // { // decimal lat = 0; // decimal lon = 0; // if (j % 2 == 0) // { // lat = (decimal)polygonCoordinates[i].Values().ElementAt(j); // } // else // { // lon = (decimal)polygonCoordinates[i].Values().ElementAt(j); // } // } //} } else if ((string)geometryType == "MultiPoint") { } else if ((string)geometryType == "MultiLineString") { } } } return(features); }
public static void SlicePaths(Data.Layer layer, Vector2 p0, Vector2 p1, bool breakPaths = true) { var openSplitPoints = new HashSet <Data.Point>(); var splitPoints = new List <Data.Point>(); var verbatimPaths = new HashSet <Data.Path>(); foreach (var path in layer.Paths) { var isOpen = path.IsOpen; var hasCuts = false; var skip = 0; foreach (var segment in SustainedSegments(path)) { if (skip > 0) { --skip; } else { var prev = 1f; foreach (var t in segment.IntersectLine(p0, p1) .Select(loc => loc.Item2) .OrderByDescending(t => t)) { var otherSegment = segment.SplitAt(t / prev); foreach (var point in Enumerable.Concat(segment.Points, otherSegment.OffCurves)) { point.X = Outline.RoundToGrid(point.X); point.Y = Outline.RoundToGrid(point.Y); } if (!breakPaths) { segment.OnCurve.IsSelected = true; } else if (isOpen) { openSplitPoints.Add(segment.OnCurve); } else { splitPoints.Add(segment.OnCurve); } skip += 1; prev = t; } } hasCuts |= skip > 0; } if (!hasCuts) { verbatimPaths.Add(path); } } if (splitPoints.Count >= 2 || openSplitPoints.Count > 0) { // Sort segments by distance of the split point from p0 and build graph of pairs var jumpsDict = new Dictionary <Data.Point, SplitIterator>(); { var reference = p1 - p0; var processedPaths = new HashSet <Data.Path>(); var sortedPoints = splitPoints.OrderBy(point => (point.ToVector2() - p0).LengthSquared()) .ToList(); if (sortedPoints.Count % 2 > 0) { // TODO: currently we remove the last point, but we could rather find the undesired point openSplitPoints.Add(sortedPoints.Last()); sortedPoints.RemoveAt(sortedPoints.Count - 1); } foreach (var(split1, split2) in ByTwo(sortedPoints)) { // After our jump, we want to go back to the same side of the slice, // i.e. have from and to running opposite sides of it if (!processedPaths.Contains(split1.Parent) && !processedPaths.Contains(split2.Parent) && !RunningOppositeSides(split1, split2, reference)) { var path = split2.Parent; path.Reverse(); // Add split1 and split2 to the set of altered direction paths, to not touch those again later processedPaths.Add(path); processedPaths.Add(split1.Parent); } jumpsDict[split1] = new SplitIterator(split2); jumpsDict[split2] = new SplitIterator(split1); } } var result = new List <Data.Path>(); foreach (var path in layer.Paths) { if (verbatimPaths.Contains(path)) { result.Add(path); } else if (path.IsOpen) { foreach (var segment in path.Segments.AsEnumerable().Reverse()) { var onCurve = segment.OnCurve; if (openSplitPoints.Contains(onCurve)) { result.Add(BreakPath(path, path.Points.IndexOf(onCurve))); } } result.Add(path); } else { foreach (var segment in path.Segments) { var onCurve = segment.OnCurve; if (jumpsDict.ContainsKey(onCurve)) { result.Add(WalkPath(onCurve, jumpsDict)); } } } } layer.Paths.Clear(); layer.Paths.AddRange(result); } }
public static void DrawFill(Data.Layer layer, CanvasDrawingSession ds, float rescale, Color color) { ds.FillGeometry(layer.ClosedCanvasPath, color); }
public static void DrawGuidelines(Data.Layer layer, CanvasDrawingSession ds, float rescale, Data.Geometry.Rect drawingRect) { var halfSize = 4 * rescale; var selectedHalfSize = 5 * rescale; (IEnumerable <Data.Guideline>, Color)[] drawingPlan =
static (float, float) GetLayerMetrics(Data.Layer layer) => layer.Master is Data.Master master ?