Aetheria/Assets/Scripts/NIH/MSAGL/Routing/ShapeObstacleCalculator.cs
hyperion51 01a956eef6 MSAGL Support
Added new tech tree layout implementation using Microsoft Automatic Graph Layouts
Added some functionality to the database editor tools
2020-04-14 00:42:04 +01:00

108 lines
No EOL
4.8 KiB
C#

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Microsoft.Msagl.Core.DataStructures;
using Microsoft.Msagl.Core.Geometry;
using Microsoft.Msagl.Core.Geometry.Curves;
using Microsoft.Msagl.Core.GraphAlgorithms;
using Microsoft.Msagl.Routing.Visibility;
namespace Microsoft.Msagl.Routing {
/// <summary>
/// The class calculates obstacles under the shape.
/// We assume that the boundaries are not set for the shape children yet
/// </summary>
internal class ShapeObstacleCalculator {
RectangleNode<Polyline> tightHierarchy;
RectangleNode<TightLooseCouple> coupleHierarchy;
public RectangleNode<Shape> RootOfLooseHierarchy { get; set; }
internal ShapeObstacleCalculator(Shape shape, double tightPadding, double loosePadding,
Dictionary<Shape, TightLooseCouple> shapeToTightLooseCouples) {
MainShape = shape;
TightPadding = tightPadding;
LoosePadding = loosePadding;
ShapesToTightLooseCouples = shapeToTightLooseCouples;
}
Dictionary<Shape, TightLooseCouple> ShapesToTightLooseCouples { get; set; }
double TightPadding { get; set; }
double LoosePadding { get; set; }
Shape MainShape { get; set; }
internal bool OverlapsDetected { get; set; }
internal void Calculate() {
if (MainShape.Children.Count() == 0) return;
CreateTightObstacles();
CreateTigthLooseCouples();
FillTheMapOfShapeToTightLooseCouples();
}
void FillTheMapOfShapeToTightLooseCouples() {
var childrenShapeHierarchy =
RectangleNode<Shape>.CreateRectangleNodeOnEnumeration(
MainShape.Children.Select(s => new RectangleNode<Shape>(s, s.BoundingBox)));
RectangleNodeUtils.CrossRectangleNodes(childrenShapeHierarchy, coupleHierarchy,
TryMapShapeToTightLooseCouple);
}
void TryMapShapeToTightLooseCouple(Shape shape, TightLooseCouple tightLooseCouple) {
if (ShapeIsInsideOfPoly(shape, tightLooseCouple.TightPolyline))
ShapesToTightLooseCouples[shape] = tightLooseCouple;
#if TEST_MSAGL
tightLooseCouple.LooseShape.UserData = (string) shape.UserData + "x";
#endif
}
/// <summary>
/// this test is valid in our situation were the tight polylines are disjoint and the shape can cross only one of them
/// </summary>
/// <param name="shape"></param>
/// <param name="tightPolyline"></param>
/// <returns></returns>
static bool ShapeIsInsideOfPoly(Shape shape, Polyline tightPolyline) {
return Curve.PointRelativeToCurveLocation(shape.BoundaryCurve.Start, tightPolyline) == PointLocation.Inside;
}
void CreateTigthLooseCouples() {
var couples = new List<TightLooseCouple>();
foreach (var tightPolyline in tightHierarchy.GetAllLeaves()) {
var distance = InteractiveObstacleCalculator.FindMaxPaddingForTightPolyline(tightHierarchy, tightPolyline, LoosePadding);
var loosePoly = InteractiveObstacleCalculator.LoosePolylineWithFewCorners(tightPolyline, distance);
couples.Add(new TightLooseCouple(tightPolyline, new Shape(loosePoly), distance));
}
coupleHierarchy = RectangleNode<TightLooseCouple>.
CreateRectangleNodeOnEnumeration(couples.Select(c => new RectangleNode<TightLooseCouple>(c, c.TightPolyline.BoundingBox)));
}
void CreateTightObstacles() {
var tightObstacles = new Set<Polyline>(MainShape.Children.Select(InitialTightPolyline));
int initialNumberOfTightObstacles = tightObstacles.Count;
tightHierarchy = InteractiveObstacleCalculator.RemovePossibleOverlapsInTightPolylinesAndCalculateHierarchy(tightObstacles);
OverlapsDetected = initialNumberOfTightObstacles > tightObstacles.Count;
}
Polyline InitialTightPolyline(Shape shape) {
var poly = InteractiveObstacleCalculator.PaddedPolylineBoundaryOfNode(shape.BoundaryCurve, TightPadding);
var stickingPointsArray = LoosePolylinesUnderShape(shape).SelectMany(l => l).Where(
p => Curve.PointRelativeToCurveLocation(p, poly) == PointLocation.Outside).ToArray();
if (stickingPointsArray.Length <= 0) return poly;
return new Polyline(
ConvexHull.CalculateConvexHull(poly.Concat(stickingPointsArray))) {
Closed = true
};
}
IEnumerable<Polyline> LoosePolylinesUnderShape(Shape shape) {
return shape.Children.Select(child => (Polyline)(ShapesToTightLooseCouples[child].LooseShape.BoundaryCurve));
}
}
}