LinkedList <MetroEdge> SortAdjacentEdges(int v, List <MetroEdge> adjacent) { MetroEdge mn = adjacent.First(); int mnv = OppositeNode(mn, v); adjacent.Sort(delegate(MetroEdge edge1, MetroEdge edge2) { int a = OppositeNode(edge1, v); int b = OppositeNode(edge2, v); //TODO: remove angles! double angA = Point.Angle(positions[a] - positions[v], positions[mnv] - positions[v]); double angB = Point.Angle(positions[b] - positions[v], positions[mnv] - positions[v]); return(angA.CompareTo(angB)); }); LinkedList <MetroEdge> res = new LinkedList <MetroEdge>(); foreach (MetroEdge edge in adjacent) { LinkedListNode <MetroEdge> node = res.AddLast(edge); adjacencyIndex.Add(new Tuple <int, MetroEdge>(v, edge), node); } return(res); }
/// <summary> /// offsets the curve in the given direction /// </summary> /// <param name="offset">the width of the offset</param> /// <param name="dir">the direction of the offset</param> /// <returns></returns> public ICurve OffsetCurve(double offset, Point dir) { //is dir inside or outside Point d = dir - center; double angle = Point.Angle(aAxis, d); Point s = aAxis * Math.Cos(angle) + bAxis * Math.Sin(angle); if (s.Length < d.Length) { double al = aAxis.Length; double bl = bAxis.Length; return(new Ellipse((al + offset) * aAxis.Normalize(), (bl + offset) * bAxis.Normalize(), center)); } { double al = aAxis.Length; double bl = bAxis.Length; #if DEBUGCURVES if (al < offset || bl < offset) { throw new Exception("wrong parameter for ellipse offset"); } #endif return(new Ellipse((al - offset) * aAxis.Normalize(), (bl - offset) * bAxis.Normalize(), center)); } }
static Dictionary <GeomEdge, double> GetMiddleAnglesOfMultiedge(List <GeomEdge> multiedge, GeomNode node) { var ret = new Dictionary <GeomEdge, double>(); GeomEdge firstEdge = multiedge[0]; Point a = node.Center; Point b = Middle(firstEdge.Curve); ret[firstEdge] = 0; for (int i = 1; i < multiedge.Count; i++) { GeomEdge edge = multiedge[i]; Point c = Middle(edge.Curve); double angle = Point.Angle(b, a, c); if (angle > Math.PI) { angle = angle - Math.PI * 2; } ret[edge] = angle; } return(ret); }
bool AngleIsTooSmallAfterShortcutAtVertex(VisibilityVertex v1, VisibilityVertex v2, VisibilityVertex v3) { foreach (var edge in v1.OutEdges) { var t = edge.Target; if (t == v3 || t == v2) { continue; } //LayoutAlgorithmSettings.ShowDebugCurves(new DebugCurve(1, "red", new LineSegment(v3.Point, v1.Point)), //new DebugCurve(1, "blue", new LineSegment(v1.Point, t.Point))); if (AngleIsTooSmall(Point.Angle(v3.Point, v1.Point, t.Point))) { return(true); } } foreach (var edge in v1.InEdges) { var t = edge.Source; if (t == v3 || t == v2) { continue; } if (AngleIsTooSmall(Point.Angle(v3.Point, v1.Point, t.Point))) { return(true); } } return(false); }
/// <summary> /// Computes the standard deviation of the edge length change for a set of given edges. /// </summary> /// <param name="graphOld"></param> /// <param name="graphNew"></param> /// <param name="proximityEdges"></param> /// <returns></returns> public static Tuple <String, double> RotationAngleMean(GeometryGraph graphOld, GeometryGraph graphNew, HashSet <Tuple <int, int> > proximityEdges) { if (proximityEdges.Count == 0) { return(Tuple.Create("RotationAngleMean", -1.0)); } double meanRotationAngle = 0; int n = proximityEdges.Count; foreach (var p in proximityEdges) { var oldDir = graphOld.Nodes[p.Item1].Center - graphOld.Nodes[p.Item2].Center; var newDir = graphNew.Nodes[p.Item1].Center - graphNew.Nodes[p.Item2].Center; double angle = Point.Angle(oldDir, newDir); Debug.Assert(angle >= 0); if (angle > Math.PI) { angle = 2 * Math.PI - angle; } Debug.Assert(angle >= 0); meanRotationAngle += angle; } meanRotationAngle /= n; meanRotationAngle *= (180 / Math.PI); return(Tuple.Create("RotationAngleMean", meanRotationAngle)); }
/// <summary> /// Radius we need to draw to separate adjacent bundles ab and ac /// </summary> internal static double GetMinRadiusForTwoAdjacentBundles(double r, Point a, Point b, Point c, double widthAB, double widthAC, MetroGraphData metroGraphData, BundlingSettings bundlingSettings) { if (widthAB < ApproximateComparer.DistanceEpsilon || widthAC < ApproximateComparer.DistanceEpsilon) { return(r); } double angle = Point.Angle(b, a, c); angle = Math.Min(angle, Math.PI * 2 - angle); if (angle < ApproximateComparer.DistanceEpsilon) { return(2 * bundlingSettings.MaxHubRadius); } if (angle >= Math.PI / 2) { return(r * 1.05); } //find the intersection point of two bundles double sina = Math.Sin(angle); double cosa = Math.Cos(angle); double aa = widthAB / (4 * sina); double bb = widthAC / (4 * sina); double d = 2 * Math.Sqrt(aa * aa + bb * bb + 2 * aa * bb * cosa); d = Math.Min(d, 2 * bundlingSettings.MaxHubRadius); d = Math.Max(d, r); return(d); }
string EllipseToString(Ellipse ellipse) { string largeArc = Math.Abs(ellipse.ParEnd-ellipse.ParStart) >= Math.PI? "1":"0"; string sweepFlag= ellipse.OrientedCounterclockwise()?"1":"0"; return String.Join(" ", "A", EllipseRadiuses(ellipse), DoubleToString(Point.Angle(new Point(1, 0), ellipse.AxisA) / (Math.PI / 180.0)), largeArc, sweepFlag, PointsToString(ellipse.End)); }
//private void ProcessLeftSideOfTrapez(ref int p1, ref int p2, ref int q2, ref int q1) { // //the closest vertex is on the left side // Point pn1 = P.Pnt(p1); Point pn2 = P.Pnt(p2); // Point qn1 = Q.Pnt(q1); Point qn2 = Q.Pnt(q2); // //SugiyamaLayoutSettings.Show(new LineSegment(pn1, pn2), new LineSegment(pn2, qn2), new LineSegment(qn2, qn1), new LineSegment(qn1, pn1)); // double ap1 = Point.Angle(pn2, pn1, qn1); // double aq1 = Point.Angle(pn1, qn1, qn2); // System.Diagnostics.Debug.Assert(ap1 + aq1 >= Math.PI); // //the point is on the left side // if (ap1 >= Math.PI / 2 && aq1 >= Math.PI / 2) { // q2 = q1; //the vertices of the left side gives the solution // p2 = p1; // } else if (ap1 < Math.PI / 2) { // q2 = q1; // if (!Point.CanProject(qn1, pn1, pn2)) // p1 = p2; // } else { //aq1<Pi/2 // p2 = p1; // if (!Point.CanProject(pn1, qn1, qn2)) // q1 = q2; // } //} void GetAnglesAtTheMedian(int mp, int mq, ref Point mP, ref Point mQ, out double a1, out double a2, out double b1, out double b2) { a1 = Point.Angle(mQ, mP, P.Pnt(P.Prev(mp))); a2 = Point.Angle(P.Pnt(P.Next(mp)), mP, mQ); b1 = Point.Angle(Q.Pnt(Q.Next(mq)), mQ, mP); b2 = Point.Angle(mP, mQ, Q.Pnt(Q.Prev(mq))); }
int CompareByAngleFromNodeCenter(VisibilityVertex a, VisibilityVertex b, Point center) { var x = new Point(1, 0); var aAngle = Point.Angle(x, a.Point - center); var bAngle = Point.Angle(x, b.Point - center); return(aAngle.CompareTo(bAngle)); }
void ModifyEdgeByScale(Point delta, GeomEdge edge) { //StraightLineEdges.CreateSimpleEdgeCurveWithUnderlyingPolyline(edge); var sn = edge.Source.UserData as Drawing.Node; var tn = edge.Target.UserData as Drawing.Node; //var gg = graph.UserData as Graph; //var vsn = Viewer.GetIViewerObject(sn); //var vtn = Viewer.GetIViewerObject(tn); Drawing.Node oN = null, tN = null; if (Viewer.GetIViewerObject(sn).MarkedForDragging) { tN = sn; oN = tn; } else { tN = tn; oN = sn; } Point o = oN.Pos, t = tN.Pos, t_ = t - delta; double scale = (t - o).Length / (t_ - o).Length; //double angle = Point.Angle(t, o, t_)*180/Math.PI; double angle = Point.Angle(t, o, t_); System.Windows.Media.Matrix mm = System.Windows.Media.Matrix.Identity; //mm.ScaleAt(scale, scale, o.X, o.Y); mm.RotateAt(angle, o.X, o.Y); //PlaneTransformation mt = new PlaneTransformation(mm.M11,mm.M12,mm.OffsetX,mm.M21,mm.M22,mm.OffsetY); var scaleMatrix = new PlaneTransformation(scale, 0, 0, 0, scale, 0); var translateToOrigin = new PlaneTransformation(1, 0, -o.X, 0, 1, -o.Y); var translateToNode = new PlaneTransformation(1, 0, o.X, 0, 1, o.Y); var rotateMatrix = PlaneTransformation.Rotation(-angle); var matrix = translateToNode * scaleMatrix * rotateMatrix * translateToOrigin; if (edge.UnderlyingPolyline != null) { var ul = edge.UnderlyingPolyline; if (tN == sn) { ul.HeadSite.Point = t; } else { ul.LastSite.Point = t; } for (Site s = ul.HeadSite.Next; s != ul.LastSite; s = s.Next) { s.Point = matrix * s.Point; } edge.Curve = ul.CreateCurve(); Arrowheads.TrimSplineAndCalculateArrowheads(edge, edge.Curve, true, false); } //edge.Curve = edge.Curve.Transform(matrix); //var angle= Point.Angle(graph.) }
private Func <int, double> GetSequenceDelegate(Point point) { Point pointOfP = Pnt(0); return(delegate(int i) { double d = Point.Angle(pointOfP, point, Pnt(i)); return d < Math.PI ? d : d - 2 * Math.PI; }); }
static void SortPointByAngles(LgNodeInfo nodeInfo, Point[] polySplitArray) { var angles = new double[polySplitArray.Length]; for (int i = 0; i < polySplitArray.Length; i++) { angles[i] = Point.Angle(new Point(1, 0), polySplitArray[i] - nodeInfo.Center); } Array.Sort(angles, polySplitArray); }
void SnapToAfterBefore(VisibilityVertex v, RbTree <VisibilityVertex> nodeBoundaryRbTree, Point center, Dictionary <VisibilityEdge, VisibilityVertex> ret, VisibilityEdge e) { VisibilityVertex beforeV, afterV; FindBeforeAfterV(v, nodeBoundaryRbTree, out beforeV, out afterV, center); var beforeAngle = Point.Angle(beforeV.Point - center, v.Point - center); var afterAngle = Point.Angle(v.Point - center, afterV.Point - center); ret[e] = beforeAngle <= afterAngle ? beforeV : afterV; }
void FindBeforeAfterV(VisibilityVertex v, RbTree <VisibilityVertex> nodeBoundaryRbTree, out VisibilityVertex beforeV, out VisibilityVertex afterV, Point center) { Point xDir = new Point(1, 0); var vAngle = Point.Angle(xDir, v.Point - center); var rNode = nodeBoundaryRbTree.FindLast(w => Point.Angle(xDir, w.Point - center) <= vAngle); beforeV = rNode != null ? rNode.Item : nodeBoundaryRbTree.TreeMaximum().Item; rNode = nodeBoundaryRbTree.FindFirst(w => Point.Angle(xDir, w.Point - center) >= vAngle); afterV = rNode != null ? rNode.Item : nodeBoundaryRbTree.TreeMinimum().Item; }
public static Polyline RemoveLeastSignificantVertices(this Polyline polyline, double smallestAcceptableAngle = Tolerance.Angle, double angleTolerance = Tolerance.Angle, double distanceTolerance = Tolerance.Distance) { List <Point> pnts = polyline.DiscontinuityPoints(distanceTolerance, angleTolerance); Point originalLastPoint = pnts.Last(); int startIndex = 0; int maxIndex = polyline.IsClosed(distanceTolerance) ? pnts.Count : pnts.Count - 2; while (startIndex < maxIndex) { Point first = pnts[startIndex]; Point second = pnts[(startIndex + 1) % pnts.Count]; Point third = pnts[(startIndex + 2) % pnts.Count]; if (first.Angle(second, third) <= smallestAcceptableAngle) { pnts.RemoveAt((startIndex + 1) % pnts.Count); //Delete the second point from the list, it's not necessary maxIndex--; } else { startIndex++; //Move onto the next point } } if (polyline.IsClosed(distanceTolerance)) //Only re-close if original polyline is closed { pnts.Add(pnts.First()); } Polyline pLine = new Polyline() { ControlPoints = pnts, }; List <double> angles = new List <double>(); foreach (BH.oM.Geometry.Point point in pnts) { double angle = point.Angle(pnts[(pnts.IndexOf(point) + 1) % pnts.Count], pnts[(pnts.IndexOf(point) + 2) % pnts.Count]); angles.Add(angle); } foreach (double angle in angles) { if (angle < smallestAcceptableAngle) { BH.Engine.Reflection.Compute.RecordWarning("One ore more of the angles of the new polyline is smaller than smallestAcceptableAngle, choose a smaller value for smallestAcceptableAngle or proceed with the created polyline as it is."); } } return(pLine); }
//public void Rotate(double originX, double originY, double angle); public void Rotate(Point origin, double angle) { double distanceToOrigin; double angleToOrigin; for (int i = 0; i < PointsCount; ++i) { Point pt = points[i]; distanceToOrigin = pt.Distance(origin); angleToOrigin = pt.Angle(origin); points[i] = origin.MoveTo(angleToOrigin - 180 + angle, distanceToOrigin); } }
public static Polyline CleanPolyline(this Polyline polyline, double tolerance = Tolerance.Angle) { //This method is for closed polylines only at the moment if (!polyline.IsClosed()) { BH.Engine.Reflection.Compute.RecordError("The CleanPolyline method is only for closed polylines and the input polyline is not closed."); return(polyline); } List <Point> pnts = polyline.DiscontinuityPoints(); if (pnts.Count < 3) { return(polyline); //If there's only two points here then this method isn't necessary } int startIndex = 0; while (startIndex < pnts.Count) { Point first = pnts[startIndex]; Point second = pnts[(startIndex + 1) % pnts.Count]; Point third = pnts[(startIndex + 2) % pnts.Count]; if (first.Angle(second, third) <= BH.oM.Geometry.Tolerance.Angle) { //Delete the second point from the list, it's not necessary pnts.RemoveAt((startIndex + 1) % pnts.Count); } else { startIndex++; //Move onto the next point } } if (pnts.First() != pnts.Last()) { pnts.Add(pnts.First()); //Reclose polyline } Polyline pLine = new Polyline() { ControlPoints = pnts, }; return(pLine); }
void TryToGlueEdges(Station node, Station a, Station b, Dictionary <Tuple <Station, Station>, Point> gluedEdges, int step) { Debug.Assert(a != b); var angle = Point.Angle(a.Position, node.Position, b.Position); if (angle < bundlingSettings.AngleThreshold) { var la = (a.Position - node.Position).Length; var lb = (b.Position - node.Position).Length; double ratio = Math.Min(la, lb) / Math.Max(la, lb); if (ratio < 0.05) { return; } if (la < lb) { if (EdgeGluingIsAllowed(node, a, b)) { AddEdgeToGlue(node, b, a, a.Position, gluedEdges); return; } } else { if (EdgeGluingIsAllowed(node, b, a)) { AddEdgeToGlue(node, a, b, b.Position, gluedEdges); return; } } //TODO: need this??? if (step < 5 && ratio > 0.5) { Point newPosition = ConstructGluingPoint(node, a, b); if (EdgeGluingIsAllowed(node, a, b, newPosition)) { AddEdgeToGlue(node, b, a, newPosition, gluedEdges); } } } }
// Internal for testing internal void ConvertToRectangleIfClose() { if (this.PaddedPolyline.PolylinePoints.Count() != 4) { return; } // We're not a rectangle now but that may be due to rounding error, so we may be close to one. // First check that it's close to an axis. var ppt = this.PaddedPolyline.StartPoint; var nextPpt = ppt.NextOnPolyline; var testPoint = ppt.Point - nextPpt.Point; var slope = ((testPoint.X == 0) || (testPoint.Y == 0)) ? 0 : Math.Abs(testPoint.Y / testPoint.X); const double factor = 1000.0; if ((slope < factor) && (slope > (1.0 / factor))) { return; } const double radian90 = 90.0 * (Math.PI / 180.0); const double maxAngleDiff = radian90 / factor; // Now check angles. do { var nextNextPpt = nextPpt.NextOnPolyline; var angle = Point.Angle(ppt.Point, nextPpt.Point, nextNextPpt.Point); if (Math.Abs(radian90 - angle) > maxAngleDiff) { return; } ppt = nextPpt; nextPpt = nextNextPpt; } while (ppt != this.PaddedPolyline.StartPoint); this.PaddedPolyline = Curve.PolyFromBox(this.PaddedPolyline.BoundingBox); this.IsRectangle = true; Debug.Assert(this.IsPolylineRectangle(), "PaddedPolyline is not rectangular"); return; }
string EllipticalArcToString(Ellipse ellipse) { /* * rx ry x-axis-rotation large-arc-flag sweep-flag x y * */ //In general in an Msagl ellipse the axes don't have to be orthogonal: we have a possible bug here var rx = "A" + DoubleToString(ellipse.AxisA.Length); var ry = DoubleToString(ellipse.AxisB.Length); var xAxisRotation = DoubleToString(180 * Point.Angle(new Point(1, 0), ellipse.AxisA) / Math.PI); var largeArcFlag = Math.Abs(ellipse.ParEnd - ellipse.ParStart) >= Math.PI ? "1" : "0"; var sweepFlagInt = ellipse.ParEnd > ellipse.ParStart ? 1 : 0; //it happens because of the y-axis orientation down in SVG if (AxesSwapped(ellipse.AxisA, ellipse.AxisB)) { sweepFlagInt = sweepFlagInt == 1 ? 0 : 1; } var endPoint = PointToString(ellipse.End); return(string.Join(" ", new[] { rx, ry, xAxisRotation, largeArcFlag, sweepFlagInt.ToString(), endPoint })); }
/// <summary> /// Radius we need to draw two adjacent bundles ab and ac /// </summary> internal static double GetMinRadiusForTwoAdjacentBundlesOld(double r, Point a, Point b, Point c, double widthAB, double widthAC, MetroGraphData metroGraphData, BundlingSettings bundlingSettings) { if (widthAB < ApproximateComparer.DistanceEpsilon || widthAC < ApproximateComparer.DistanceEpsilon) { return(r); } double angle = Point.Angle(b, a, c); angle = Math.Min(angle, Math.PI * 2 - angle); if (angle < ApproximateComparer.DistanceEpsilon) { return(2 * bundlingSettings.MaxHubRadius); } //binary search //TODO: solve the equation double L = r; double R = 2 * bundlingSettings.MaxHubRadius; while (Math.Abs(R - L) > 0.1) { double C = (L + R) / 2; double alpha0 = Math.Asin(widthAB / (2 * C)); double alpha1 = Math.Asin(widthAC / (2 * C)); if (alpha0 + alpha1 <= angle) { R = C; } else { L = C; } } return(L); }
double GetBaseMiddleParamInDirection(BundleBase targetBase, Point sPos, Point neighbPos) { var curve = targetBase.Curve; var circle = curve as Ellipse; if (circle != null && circle.IsArc()) { return(Point.Angle(circle.AxisA, neighbPos - sPos)); } var intersections = Curve.GetAllIntersections(curve, new LineSegment(sPos, neighbPos), true); foreach (var intersectionInfo in intersections) { var xP = intersectionInfo.IntersectionPoint; if ((xP - sPos) * (xP - neighbPos) <= 0) { return(intersectionInfo.Par0); } } throw new InvalidOperationException(); }
private bool VelocityChanged(Point PuckVold, Point PuckVnew) { Point oldVelocity = PuckVold.Normalize(); Point newVelocity = PuckVnew.Normalize(); if ((PuckVnew.Norm() <= PuckVold.Norm()) && (PuckVnew.Norm() >= 0.95 * PuckVold.Norm()) && (Math.Abs(PuckVnew.Angle() - PuckVold.Angle()) < 0.06)) { return(false); } return(true); }