public static Multiply ( |
||
p | ||
f | float | |
Результат |
/// <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> /// Straightens the edges using internal data sturctures /// </summary> /// /// <param name="groupsToStraighten"> /// Groups of edges that should be straightened /// </param> /// /// <param name="s"> /// Specifies the amount of straightening, from 0 to 1 /// </param> private void StraightenEdgesInternally(Dictionary <KeyPair, EdgeGroupData> groupsToStraighten, float s) { foreach (EdgeGroupData ed in groupsToStraighten.Values) { for (int i = 0; i < subdivisionPoints; i++) { PointF p = ed.controlPoints[i]; p = VectorTools.Multiply(p, 1 - s) + new SizeF(VectorTools.Multiply(ed.v1 + new SizeF(VectorTools.Multiply(ed.v2 - new SizeF(ed.v1), 1.0f * (i + 1) / (subdivisionPoints + 1))), s)); ed.controlPoints[i].X = p.X; ed.controlPoints[i].Y = p.Y; } } }
/// <summary> /// Finds an intersection point of the two lines /// </summary> /// /// <param name="p1"> /// First point of the first line /// </param> /// /// <param name="p2"> /// Second point of the first line /// </param> /// /// <param name="q1"> /// First point of the second line /// </param> /// /// <param name="q2"> /// Second point of the second line /// </param> /// /// <param name="intersection"> /// Point of intersection /// </param> /// /// <param name="rp"> /// Parameter used for determining on which segment the intersection point lies /// </param> /// /// <returns> /// True if lines are not parallel, false otherwise /// </returns> private bool Intersects(PointF p1, PointF p2, PointF q1, PointF q2, ref PointF intersection, ref float rp) { float q = (p1.Y - q1.Y) * (q2.X - q1.X) - (p1.X - q1.X) * (q2.Y - q1.Y); float d = (p2.X - p1.X) * (q2.Y - q1.Y) - (p2.Y - p1.Y) * (q2.X - q1.X); if (d == 0) // parallel lines { return(false); } float r = q / d; q = (p1.Y - q1.Y) * (p2.X - p1.X) - (p1.X - q1.X) * (p2.Y - p1.Y); float s = q / d; intersection = p1 + new SizeF(VectorTools.Multiply(p2 - new SizeF(p1), r)); return(true); }
/// <summary> /// Moves the control points of all the edges of the graph closer to their original position on the straight edge /// </summary> /// /// <param name="graph"> /// Graph whose edges should be straightened /// </param> /// /// <param name="s"> /// Specifies the amount of straightening, from 0 to 1 /// </param> public void StraightenEdges(IGraph graph, float s) { foreach (IEdge e in graph.Edges) { if (e.IsSelfLoop) { continue; } PointF[] controlPoints = (PointF[])e.GetValue(ReservedMetadataKeys.PerEdgeIntermediateCurvePoints); PointF[] newControlPoints = new PointF[controlPoints.Length]; for (int i = 0; i < controlPoints.Length; i++) { PointF p = controlPoints[i]; p = VectorTools.Multiply(p, 1 - s) + new SizeF(VectorTools.Multiply(e.Vertices[0].Location + new SizeF(VectorTools.Multiply(e.Vertices[1].Location - new SizeF(e.Vertices[0].Location), 1.0f * (i + 1) / (controlPoints.Length + 1))), s)); newControlPoints[i].X = p.X; newControlPoints[i].Y = p.Y; } e.SetValue(ReservedMetadataKeys.PerEdgeIntermediateCurvePoints, newControlPoints); } }
/// <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(); } }