public GroupPairData(float cc, EdgeGroupData e1, EdgeGroupData e2, bool dd) { c = cc; ed1 = e1; ed2 = e2; d = dd; }
/// <summary> /// Divides an edge into segments by adding subdivision points to it /// </summary> /// /// <param name="ed"> /// Edge data that is used for creating new subdivision points /// </param> /// /// <param name="subdivisionPointsNum"> /// Number of subdivision points that should be created /// </param> private void DivideEdge(EdgeGroupData ed, int subdivisionPointsNum) { float r = ed.length / (subdivisionPointsNum + 1); PointF[] sPoints = new PointF[subdivisionPointsNum]; ed.newControlPoints = new PointF[subdivisionPointsNum]; PointF move; if (ed.length == 0) { move = new PointF(0, 0); } else { move = VectorTools.Multiply(ed.v2 - new SizeF(ed.v1), 1f / ed.length); } for (int i = 0; i < subdivisionPointsNum; i++) { sPoints[i] = ed.v1 + new SizeF(VectorTools.Multiply(move, r * (i + 1))); } ed.controlPoints = sPoints; ed.k = springConstant * (subdivisionPointsNum + 1) / ed.length; if (ed.k > 0.5f) { ed.k = 0.5f; } }
/// <summary> /// Divides an edge into segments by adding subdivision points to it /// </summary> /// /// <param name="ed"> /// Edge data that is used for creating new subdivision points /// </param> /// /// <param name="subdivisionPointsNum"> /// Number of subdivision points that should be created /// </param> private void DivideEdge(EdgeGroupData ed, int subdivisionPointsNum) { var r = ed.length / (subdivisionPointsNum + 1); var sPoints = new Point[subdivisionPointsNum]; ed.newControlPoints = new Point[subdivisionPointsNum]; Point move; if (ed.length == 0) { move = new Point(0, 0); } else { move = VectorTools.Multiply(VectorTools.Minus(ed.v2, ed.v1), 1f / ed.length); } for (var i = 0; i < subdivisionPointsNum; i++) { sPoints[i] = VectorTools.Plus(ed.v1, VectorTools.Multiply(move, r * (i + 1))); } ed.controlPoints = sPoints; ed.k = springConstant * (subdivisionPointsNum + 1) / ed.length; if (ed.k > 0.5f) { ed.k = 0.5f; } }
/// <summary> /// Collects data from the specified edge /// </summary> /// /// <param name="e"> /// Edge to collect data from /// </param> private void AddEdgeData(IEdge e) { EdgeGroupData ed; KeyPair key = new KeyPair(e.Vertices[0].ID, e.Vertices[1].ID); edgeGroupData.TryGetValue(key, out ed); if (ed == null) { PointF p1 = e.Vertices[0].Location; PointF p2 = e.Vertices[1].Location; ed = new EdgeGroupData(); ed.v1 = p1; ed.v2 = p2; ed.id = key; PointF mid = VectorTools.MidPoint(p1, p2); ed.middle = mid; ed.length = VectorTools.Distance(p1, p2); ed.compatibleGroups = new Dictionary <KeyPair, GroupPairData>(); //ed.edges = new HashSet<int>(); ed.edgeCount = 0; edgeGroupData.Add(key, ed); } //ed.edges.Add(e.ID); ed.edgeCount++; }
public GroupPairData(float cc, EdgeGroupData e1, EdgeGroupData e2, bool dd) { C = cc; Ed1 = e1; Ed2 = e2; D = dd; }
/// <summary> /// Collects data from the specified edge /// </summary> /// /// <param name="e"> /// Edge to collect data from /// </param> private void AddEdgeData(TEdge e) { EdgeGroupData ed; var key = new KeyPair(e.Source.ID, e.Target.ID); edgeGroupData.TryGetValue(key, out ed); if (ed == null) { var p1 = VertexPositions[e.Source]; // e.Vertices[0].Location; var p2 = VertexPositions[e.Target]; //e.Vertices[1].Location; ed = new EdgeGroupData(); ed.v1 = p1; ed.v2 = p2; ed.id = key; var mid = VectorTools.MidPoint(p1, p2); ed.middle = mid; ed.length = VectorTools.Distance(p1, p2); ed.compatibleGroups = new Dictionary <KeyPair, GroupPairData>(); //ed.edges = new HashSet<int>(); ed.edgeCount = 0; edgeGroupData.Add(key, ed); } //ed.edges.Add(e.ID); ed.edgeCount++; }
/// <summary> /// Calculates visibility coefficient of the two edges. /// </summary> /// /// <param name="ed1"> /// First edge to be used in calculation /// </param> /// /// <param name="ed2"> /// Second edge to be used in calculation /// </param> /// /// <returns> /// Compatibility coefficient ranging from 0 to 1 /// </returns> private float VisibilityCoefficient(EdgeGroupData ed1, EdgeGroupData ed2) { float c; var p1 = ed1.v1; var p2 = ed1.v2; var q1 = ed2.v1; var q2 = ed2.v2; var pn = new Point(); pn.X = p1.Y - p2.Y; pn.Y = p2.X - p1.X; var pn1 = VectorTools.Plus(pn, p1); var pn2 = VectorTools.Plus(pn, p2); var i1 = new Point(); var i2 = new Point(); float r1 = 0, r2 = 0; if (!Intersects(q1, q2, p1, pn1, ref i1, ref r1)) { return(0); } Intersects(q1, q2, p2, pn2, ref i2, ref r2); if ((r1 < 0 && r2 < 0) || (r1 > 1 && r2 > 1)) { return(0); } var im = VectorTools.MidPoint(i1, i2); var qm = ed2.middle; var i = VectorTools.Distance(i1, i2); var m = VectorTools.Distance(qm, im); if (i == 0) { return(0); } c = 1f - 2f * m / i; if (c < 0) { return(0); } else { return(c); } }
/// <summary> /// Calculates visibility coefficient of the two edges. /// </summary> /// /// <param name="ed1"> /// First edge to be used in calculation /// </param> /// /// <param name="ed2"> /// Second edge to be used in calculation /// </param> /// /// <returns> /// Compatibility coefficient ranging from 0 to 1 /// </returns> private float VisibilityCoefficient(EdgeGroupData ed1, EdgeGroupData ed2) { float c; PointF p1 = ed1.v1; PointF p2 = ed1.v2; PointF q1 = ed2.v1; PointF q2 = ed2.v2; PointF pn = new PointF(); pn.X = p1.Y - p2.Y; pn.Y = p2.X - p1.X; PointF pn1 = pn + new SizeF(p1); PointF pn2 = pn + new SizeF(p2); PointF i1 = new PointF(); PointF i2 = new PointF(); float r1 = 0, r2 = 0; if (!Intersects(q1, q2, p1, pn1, ref i1, ref r1)) { return(0); } Intersects(q1, q2, p2, pn2, ref i2, ref r2); if ((r1 < 0 && r2 < 0) || (r1 > 1 && r2 > 1)) { return(0); } PointF im = VectorTools.MidPoint(i1, i2); PointF qm = ed2.middle; float i = VectorTools.Distance(i1, i2); float m = VectorTools.Distance(qm, im); if (i == 0) { return(0); } c = 1f - 2f * m / i; if (c < 0) { return(0); } else { return(c); } }
/// <summary> /// Calculates position compatibility of the two edges /// </summary> /// /// <param name="ed1"> /// First edge to be used in calculation /// </param> /// /// <param name="ed2"> /// Second edge to be used in calculation /// </param> /// /// <returns> /// Position compatibility coefficient ranging from 0 to 1 /// </returns> private float PositionCompatibility(EdgeGroupData ed1, EdgeGroupData ed2) { float avg = (ed1.length + ed2.length) / 2; float dis = VectorTools.Distance(ed1.middle, ed2.middle); if ((avg + dis) == 0) { return(0); } return(avg / (avg + dis)); }
/// <summary> /// Calculates directedness of the two edges. /// </summary> /// /// <param name="ed1"> /// First edge to be used in calculation /// </param> /// /// <param name="ed2"> /// Second edge to be used in calculation /// </param> /// /// <returns> /// True if edges have roughly the same direction, false otherwise /// </returns> private bool CalculateDirectedness(EdgeGroupData ed1, EdgeGroupData ed2) { if ((VectorTools.Distance(ed1.v1, ed2.v1) + VectorTools.Distance(ed1.v2, ed2.v2)) < (VectorTools.Distance(ed1.v1, ed2.v2) + VectorTools.Distance(ed1.v2, ed2.v1))) { return(true); } else { return(false); } }
/// <summary> /// Calculates visibility compatibility of the two edges. /// Uses lower of the two calculated visibility coefficients. /// </summary> /// /// <param name="ed1"> /// First edge to be used in calculation /// </param> /// /// <param name="ed2"> /// Second edge to be used in calculation /// </param> /// /// <returns> /// Visibility compatibility coefficient ranging from 0 to 1 /// </returns> private float VisibilityCompatibility(EdgeGroupData ed1, EdgeGroupData ed2) { float c1, c2; c1 = VisibilityCoefficient(ed1, ed2); if (c1 == 0) { return(0); } c2 = VisibilityCoefficient(ed2, ed1); return(Math.Min(c1, c2)); }
/// <summary> /// Calculates scale compatibility of the two edges /// </summary> /// /// <param name="ed1"> /// First edge to be used in calculation /// </param> /// /// <param name="ed2"> /// Second edge to be used in calculation /// </param> /// /// <returns> /// Scale compatibility coefficient ranging from 0 to 1 /// </returns> private float ScaleCompatibility(EdgeGroupData ed1, EdgeGroupData ed2) { float l1 = ed1.length; float l2 = ed2.length; float l = l1 + l2; if (l == 0) { return(0); } else { float ret = 4 * l1 * l2 / (l * l); return(ret * ret); } }
/// <summary> /// Calculates scale compatibility of the two edges /// </summary> /// /// <param name="ed1"> /// First edge to be used in calculation /// </param> /// /// <param name="ed2"> /// Second edge to be used in calculation /// </param> /// /// <returns> /// Scale compatibility coefficient ranging from 0 to 1 /// </returns> private float ScaleCompatibility(EdgeGroupData ed1, EdgeGroupData ed2) { var l1 = ed1.Length; var l2 = ed2.Length; var l = l1 + l2; if (l == 0) { return(0); } else { var ret = 4 * l1 * l2 / (l * l); return(ret * ret); } }
/// <summary> /// Doubles subdivision points for an edge by adding one new subdivision point between each two /// </summary> /// /// <param name="ed"> /// Edge data that contains subdivision points to be doubled /// </param> private void DoubleSubdivisionPoints(EdgeGroupData ed) { if (subdivisionPoints == 0) //make one subdivision point { ed.k = springConstant * 2 / ed.length; if (ed.k > 0.5f) { ed.k = 0.5f; } ed.controlPoints = new Point[1]; ed.newControlPoints = new Point[1]; ed.controlPoints[0] = ed.middle; return; } var sPoints = ed.controlPoints; var sPointsDoubled = new Point[subdivisionPoints * 2 + 1]; ed.newControlPoints = new Point[subdivisionPoints * 2 + 1]; for (var i = 0; i < subdivisionPoints; i++) { sPointsDoubled[i * 2 + 1] = sPoints[i]; } for (var i = 0; i < subdivisionPoints - 1; i++) { sPointsDoubled[i * 2 + 2] = VectorTools.MidPoint(sPoints[i], sPoints[i + 1]); } sPointsDoubled[0] = VectorTools.MidPoint(ed.v1, sPoints[0]); sPointsDoubled[subdivisionPoints * 2] = VectorTools.MidPoint(sPoints[subdivisionPoints - 1], ed.v2); //ed.K = springConstant * (subdivisionPoints * 2 + 2) / ed.Length; ed.k *= 2f; if (ed.k > 0.5f) { ed.k = 0.5f; } ed.controlPoints = sPointsDoubled; }
/// <summary> /// Divides an edge into segments by adding subdivision points to it /// </summary> /// /// <param name="ed"> /// Edge data that is used for creating new subdivision points /// </param> /// /// <param name="subdivisionPointsNum"> /// Number of subdivision points that should be created /// </param> private void DivideEdge(EdgeGroupData ed, int subdivisionPointsNum) { var r = ed.Length / (subdivisionPointsNum + 1); var sPoints = new Point[subdivisionPointsNum]; ed.NewControlPoints = new Point[subdivisionPointsNum]; Point move; move = ed.Length == 0 ? new Point(0, 0) : VectorTools.Multiply(VectorTools.Minus(ed.V2, ed.V1), 1f / ed.Length); for (var i = 0; i < subdivisionPointsNum; i++) { sPoints[i] = VectorTools.Plus(ed.V1, VectorTools.Multiply(move, r * (i + 1))); } ed.ControlPoints = sPoints; ed.K = _springConstant * (subdivisionPointsNum + 1) / ed.Length; if (ed.K > 0.5f) { ed.K = 0.5f; } }
/// <summary> /// Collects data from the specified edge. /// Used for edges that already have control points metadata. /// </summary> /// /// <param name="e"> /// Edge to collect data from /// </param> private void AddExistingData(IEdge e) { EdgeGroupData ed; KeyPair key = new KeyPair(e.Vertices[0].ID, e.Vertices[1].ID); edgeGroupData.TryGetValue(key, out ed); if (ed == null) { PointF p1 = e.Vertices[0].Location; PointF p2 = e.Vertices[1].Location; ed = new EdgeGroupData(); ed.v1 = p1; ed.v2 = p2; ed.id = key; PointF mid = VectorTools.MidPoint(p1, p2); ed.middle = mid; ed.length = VectorTools.Distance(p1, p2); ed.controlPoints = (PointF[])e.GetValue(ReservedMetadataKeys.PerEdgeIntermediateCurvePoints); if (subdivisionPoints == 0) { subdivisionPoints = ed.controlPoints.Length; } ed.newControlPoints = new PointF[subdivisionPoints]; ed.k = springConstant * (subdivisionPoints + 1) / ed.length; if (ed.k > 0.5f) { ed.k = 0.5f; } //ed.edges = new HashSet<int>(); ed.edgeCount = 0; ed.compatibleGroups = new Dictionary <KeyPair, GroupPairData>(); edgeGroupData.Add(key, ed); } //ed.edges.Add(e.ID); ed.edgeCount++; }
/// <summary> /// Collects data from the specified edge. /// Used for edges that already have control points metadata. /// </summary> /// /// <param name="e"> /// Edge to collect data from /// </param> private void AddExistingData(TEdge e) { EdgeGroupData ed; var key = new KeyPair(e.Source.ID, e.Target.ID); _edgeGroupData.TryGetValue(key, out ed); if (ed == null) { var p1 = VertexPositions[e.Source]; // e.Vertices[0].Location; var p2 = VertexPositions[e.Target]; //e.Vertices[1].Location; ed = new EdgeGroupData { V1 = p1, V2 = p2, ID = key }; var mid = VectorTools.MidPoint(p1, p2); ed.Middle = mid; ed.Length = VectorTools.Distance(p1, p2); ed.ControlPoints = e.RoutingPoints; //e.GetValue(ReservedMetadataKeys.PerEdgeIntermediateCurvePoints); if (_subdivisionPoints == 0) { _subdivisionPoints = ed.ControlPoints.Length; } ed.NewControlPoints = new Point[_subdivisionPoints]; ed.K = _springConstant * (_subdivisionPoints + 1) / ed.Length; if (ed.K > 0.5f) { ed.K = 0.5f; } //ed.edges = new HashSet<int>(); ed.EdgeCount = 0; ed.CompatibleGroups = new Dictionary <KeyPair, GroupPairData>(); _edgeGroupData.Add(key, ed); } //ed.edges.Add(e.ID); ed.EdgeCount++; }
/// <summary> /// Calculates compatibility of the two edges. /// Combines angle, position, scale, and visibility compatibility coefficient. /// </summary> /// /// <param name="ed1"> /// First edge to be used in calculation /// </param> /// /// <param name="ed2"> /// Second edge to be used in calculation /// </param> /// /// <returns> /// Compatibility coefficient ranging from 0 to 1 /// </returns> private float CalculateCompatibility(EdgeGroupData ed1, EdgeGroupData ed2) { float c = PositionCompatibility(ed1, ed2); if (c > threshold) { c *= ScaleCompatibility(ed1, ed2); } else { return(0); } if (c > threshold) { c *= AngleCompatibility(ed1, ed2); } else { return(0); } if (c > threshold) { c *= VisibilityCompatibility(ed1, ed2); } else { return(0); } if (c > threshold) { return(c); } else { return(0); } }
/// <summary> /// Divides an edge into segments by adding subdivision points to it /// </summary> /// /// <param name="ed"> /// Edge data that is used for creating new subdivision points /// </param> /// /// <param name="subdivisionPointsNum"> /// Number of subdivision points that should be created /// </param> private void DivideEdge(EdgeGroupData ed, int subdivisionPointsNum) { float r = ed.length / (subdivisionPointsNum + 1); PointF[] sPoints = new PointF[subdivisionPointsNum]; ed.newControlPoints = new PointF[subdivisionPointsNum]; PointF move; if (ed.length == 0) move = new PointF(0, 0); else move = VectorTools.Multiply(ed.v2 - new SizeF(ed.v1), 1f / ed.length); for (int i = 0; i < subdivisionPointsNum; i++) sPoints[i] = ed.v1 + new SizeF(VectorTools.Multiply(move, r * (i + 1))); ed.controlPoints = sPoints; ed.k = springConstant * (subdivisionPointsNum + 1) / ed.length; if (ed.k > 0.5f) ed.k = 0.5f; }
/// <summary> /// Calculates position compatibility of the two edges /// </summary> /// /// <param name="ed1"> /// First edge to be used in calculation /// </param> /// /// <param name="ed2"> /// Second edge to be used in calculation /// </param> /// /// <returns> /// Position compatibility coefficient ranging from 0 to 1 /// </returns> private float PositionCompatibility(EdgeGroupData ed1, EdgeGroupData ed2) { float avg = (ed1.length + ed2.length) / 2; float dis = VectorTools.Distance(ed1.middle, ed2.middle); if ((avg + dis) == 0) return 0; return (avg / (avg + dis)); }
/// <summary> /// Calculates angle compatibility of the two edges /// </summary> /// /// <param name="ed1"> /// First edge to be used in calculation /// </param> /// /// <param name="ed2"> /// Second edge to be used in calculation /// </param> /// /// <returns> /// Angle compatibility coefficient ranging from 0 to 1 /// </returns> private float AngleCompatibility(EdgeGroupData ed1, EdgeGroupData ed2) { float a = VectorTools.Angle(ed1.v1, ed1.v2, ed2.v1, ed2.v2); return((float)Math.Abs(Math.Cos(a))); }
/// <summary> /// Calculates scale compatibility of the two edges /// </summary> /// /// <param name="ed1"> /// First edge to be used in calculation /// </param> /// /// <param name="ed2"> /// Second edge to be used in calculation /// </param> /// /// <returns> /// Scale compatibility coefficient ranging from 0 to 1 /// </returns> private float ScaleCompatibility(EdgeGroupData ed1, EdgeGroupData ed2) { float l1 = ed1.length; float l2 = ed2.length; float l = l1 + l2; if (l == 0) return 0; else { float ret = 4 * l1 * l2 / (l * l); return ret * ret; } }
/// <summary> /// Calculates angle compatibility of the two edges /// </summary> /// /// <param name="ed1"> /// First edge to be used in calculation /// </param> /// /// <param name="ed2"> /// Second edge to be used in calculation /// </param> /// /// <returns> /// Angle compatibility coefficient ranging from 0 to 1 /// </returns> private float AngleCompatibility(EdgeGroupData ed1, EdgeGroupData ed2) { float a = VectorTools.Angle(ed1.v1, ed1.v2, ed2.v1, ed2.v2); return (float)Math.Abs(Math.Cos(a)); }
/// <summary> /// Calculates visibility compatibility of the two edges. /// Uses lower of the two calculated visibility coefficients. /// </summary> /// /// <param name="ed1"> /// First edge to be used in calculation /// </param> /// /// <param name="ed2"> /// Second edge to be used in calculation /// </param> /// /// <returns> /// Visibility compatibility coefficient ranging from 0 to 1 /// </returns> private float VisibilityCompatibility(EdgeGroupData ed1, EdgeGroupData ed2) { float c1, c2; c1 = VisibilityCoefficient(ed1, ed2); if (c1 == 0) return 0; c2 = VisibilityCoefficient(ed2, ed1); return Math.Min(c1, c2); }
/// <summary> /// Calculates visibility coefficient of the two edges. /// </summary> /// /// <param name="ed1"> /// First edge to be used in calculation /// </param> /// /// <param name="ed2"> /// Second edge to be used in calculation /// </param> /// /// <returns> /// Compatibility coefficient ranging from 0 to 1 /// </returns> private float VisibilityCoefficient(EdgeGroupData ed1, EdgeGroupData ed2) { float c; PointF p1 = ed1.v1; PointF p2 = ed1.v2; PointF q1 = ed2.v1; PointF q2 = ed2.v2; PointF pn = new PointF(); pn.X = p1.Y - p2.Y; pn.Y = p2.X - p1.X; PointF pn1 = pn + new SizeF(p1); PointF pn2 = pn + new SizeF(p2); PointF i1 = new PointF(); PointF i2 = new PointF(); float r1 = 0, r2 = 0; if (!Intersects(q1, q2, p1, pn1, ref i1, ref r1)) return 0; Intersects(q1, q2, p2, pn2, ref i2, ref r2); if ((r1 < 0 && r2 < 0) || (r1 > 1 && r2 > 1)) return 0; PointF im = VectorTools.MidPoint(i1, i2); PointF qm = ed2.middle; float i = VectorTools.Distance(i1, i2); float m = VectorTools.Distance(qm, im); if (i == 0) return 0; c = 1f - 2f * m / i; if (c < 0) return 0; else return c; }
/// <summary> /// Collects data from the specified edge. /// Used for edges that already have control points metadata. /// </summary> /// /// <param name="e"> /// Edge to collect data from /// </param> private void AddExistingData(IEdge e) { EdgeGroupData ed; KeyPair key = new KeyPair(e.Vertices[0].ID, e.Vertices[1].ID); edgeGroupData.TryGetValue(key, out ed); if (ed == null) { PointF p1 = e.Vertices[0].Location; PointF p2 = e.Vertices[1].Location; ed = new EdgeGroupData(); ed.v1 = p1; ed.v2 = p2; ed.id = key; PointF mid = VectorTools.MidPoint(p1, p2); ed.middle = mid; ed.length = VectorTools.Distance(p1, p2); ed.controlPoints = (PointF[])e.GetValue(ReservedMetadataKeys.PerEdgeIntermediateCurvePoints); if (subdivisionPoints == 0) subdivisionPoints = ed.controlPoints.Length; ed.newControlPoints = new PointF[subdivisionPoints]; ed.k = springConstant * (subdivisionPoints + 1) / ed.length; if (ed.k > 0.5f) ed.k = 0.5f; //ed.edges = new HashSet<int>(); ed.edgeCount = 0; ed.compatibleGroups = new Dictionary<KeyPair, GroupPairData>(); edgeGroupData.Add(key, ed); } //ed.edges.Add(e.ID); ed.edgeCount++; }
/// <summary> /// Calculates directedness of the two edges. /// </summary> /// /// <param name="ed1"> /// First edge to be used in calculation /// </param> /// /// <param name="ed2"> /// Second edge to be used in calculation /// </param> /// /// <returns> /// True if edges have roughly the same direction, false otherwise /// </returns> private bool CalculateDirectedness(EdgeGroupData ed1, EdgeGroupData ed2) { if ((VectorTools.Distance(ed1.v1, ed2.v1) + VectorTools.Distance(ed1.v2, ed2.v2)) < (VectorTools.Distance(ed1.v1, ed2.v2) + VectorTools.Distance(ed1.v2, ed2.v1))) return true; else return false; }
/// <summary> /// Calculates compatibility of the two edges. /// Combines angle, position, scale, and visibility compatibility coefficient. /// </summary> /// /// <param name="ed1"> /// First edge to be used in calculation /// </param> /// /// <param name="ed2"> /// Second edge to be used in calculation /// </param> /// /// <returns> /// Compatibility coefficient ranging from 0 to 1 /// </returns> private float CalculateCompatibility(EdgeGroupData ed1, EdgeGroupData ed2) { float c = PositionCompatibility(ed1, ed2); if (c > threshold) c *= ScaleCompatibility(ed1, ed2); else return 0; if (c > threshold) c *= AngleCompatibility(ed1, ed2); else return 0; if (c > threshold) c *= VisibilityCompatibility(ed1, ed2); else return 0; if (c > threshold) return c; else return 0; }
/// <summary> /// Doubles subdivision points for an edge by adding one new subdivision point between each two /// </summary> /// /// <param name="ed"> /// Edge data that contains subdivision points to be doubled /// </param> private void DoubleSubdivisionPoints(EdgeGroupData ed) { if (subdivisionPoints == 0) //make one subdivision point { ed.k = springConstant * 2 / ed.length; if (ed.k > 0.5f) ed.k = 0.5f; ed.controlPoints = new PointF[1]; ed.newControlPoints = new PointF[1]; ed.controlPoints[0] = ed.middle; return; } PointF[] sPoints = ed.controlPoints; PointF[] sPointsDoubled = new PointF[subdivisionPoints * 2 + 1]; ed.newControlPoints = new PointF[subdivisionPoints * 2 + 1]; for (int i = 0; i < subdivisionPoints; i++) sPointsDoubled[i * 2 + 1] = sPoints[i]; for (int i = 0; i < subdivisionPoints - 1; i++) sPointsDoubled[i * 2 + 2] = VectorTools.MidPoint(sPoints[i], sPoints[i + 1]); sPointsDoubled[0] = VectorTools.MidPoint(ed.v1, sPoints[0]); sPointsDoubled[subdivisionPoints * 2] = VectorTools.MidPoint(sPoints[subdivisionPoints - 1], ed.v2); //ed.K = springConstant * (subdivisionPoints * 2 + 2) / ed.Length; ed.k *= 2f; if (ed.k > 0.5f) ed.k = 0.5f; ed.controlPoints = sPointsDoubled; }
/// <summary> /// Calculates new positions for the control points of an edge by applying elastic and electrostatic forces to them /// </summary> /// /// <param name="o"> /// Edge data that contains subdivision points to be moved /// </param> private void CalculateNewControlPoints(Object o) { EdgeGroupData ed = (EdgeGroupData)o; for (int i = 0; i < subdivisionPoints; i++) { PointF p = ed.controlPoints[i]; PointF p1, p2; if (i == 0) { p1 = ed.v1; } else { p1 = ed.controlPoints[i - 1]; } if (i == (subdivisionPoints - 1)) { p2 = ed.v2; } else { p2 = ed.controlPoints[i + 1]; } SizeF sp = new SizeF(p); PointF f = VectorTools.Multiply((p1 - sp) + new SizeF((p2 - sp)), ed.k); PointF r = new PointF(0, 0); foreach (GroupPairData epd in ed.compatibleGroups.Values) { PointF q; float j = 1f; EdgeGroupData ed2; if ((epd.ed1.id.k1 == ed.id.k1) && (epd.ed1.id.k2 == ed.id.k2)) { ed2 = epd.ed2; } else { ed2 = epd.ed1; } if (epd.d) { q = ed2.controlPoints[i]; } else { q = ed2.controlPoints[subdivisionPoints - i - 1]; if (directed && repulseOpposite) { j = repulsionCoefficient; } } PointF fs = q - sp; //PointF fs = new PointF(q.X - p.X, q.Y - p.Y); float l = VectorTools.Length(fs); if (l > 0)//??? { fs = VectorTools.Multiply(fs, epd.c / (l)); //fs = VectorTools.Multiply(fs, VectorTools.Length(fs) * ed2.edges.Count); fs = VectorTools.Multiply(fs, VectorTools.Length(fs) * ed2.edgeCount); r.X += (j * fs.X); r.Y += (j * fs.Y); } } float rl = VectorTools.Length(r); if (rl > 0) { r = VectorTools.Multiply(r, (float)(1.0 / Math.Sqrt(rl))); } PointF move = new PointF(f.X + r.X, f.Y + r.Y); float moveL = VectorTools.Length(move); //float len = ed.Length / (subdivisionPoints + 1); //if (moveL > (len)) move = VectorTools.Multiply(move, len*cooldown / moveL); //if (moveL != 0) move = VectorTools.Multiply(move, cooldown / moveL); move = VectorTools.Multiply(move, cooldown * 0.5f); ed.newControlPoints[i] = move + sp; if (ed.newControlPoints[i].X < rectangle.Left) { ed.newControlPoints[i].X = rectangle.Left; } else if (ed.newControlPoints[i].X > rectangle.Right) { ed.newControlPoints[i].X = rectangle.Right; } if (ed.newControlPoints[i].Y < rectangle.Top) { ed.newControlPoints[i].Y = rectangle.Top; } else if (ed.newControlPoints[i].Y > rectangle.Bottom) { ed.newControlPoints[i].Y = rectangle.Bottom; } } if (useThreading) { sem.Release(); } }
/// <summary> /// Collects data from the specified edge /// </summary> /// /// <param name="e"> /// Edge to collect data from /// </param> private void AddEdgeData(IEdge e) { EdgeGroupData ed; KeyPair key = new KeyPair(e.Vertices[0].ID, e.Vertices[1].ID); edgeGroupData.TryGetValue(key, out ed); if (ed == null) { PointF p1 = e.Vertices[0].Location; PointF p2 = e.Vertices[1].Location; ed = new EdgeGroupData(); ed.v1 = p1; ed.v2 = p2; ed.id = key; PointF mid = VectorTools.MidPoint(p1, p2); ed.middle = mid; ed.length = VectorTools.Distance(p1, p2); ed.compatibleGroups = new Dictionary<KeyPair, GroupPairData>(); //ed.edges = new HashSet<int>(); ed.edgeCount = 0; edgeGroupData.Add(key, ed); } //ed.edges.Add(e.ID); ed.edgeCount++; }