//一括座標変換(関数オーバロード) public Vector2D Translate(Vector3D A) { Vector3D P = new Vector3D(); Vector2D R = new Vector2D(); P = ViewTranslate(A); P = ProjectionTranslate(P); R = ViewPortTranslate(P); return R; }
//ビューポート変換 public Vector2D ViewPortTranslate(Vector3D A) { Vector2D P = new Vector2D(); P.X = (float)(A.X * (w / 2) + (w / 2)); P.Y = (float)(A.Y * -(h / 2) + (h / 2)); return P; }
//一括座標変換 public Vector2D[] Translate(Vector3D[] A) { int len = A.Length; Vector3D[] P = new Vector3D[len]; Vector2D[] R = new Vector2D[len]; for (int i = 0; i < len; i++) { P[i] = new Vector3D(); R[i] = new Vector2D(); } for (int i = 0; i < len; i++) { P[i] = ViewTranslate(A[i]); P[i] = ProjectionTranslate(P[i]); R[i] = ViewPortTranslate(P[i]); } return R; }
//2つのベクトルの距離を取得 public float Getdistance(Vector2D A) { return (A - this).Getnorm(); }
//カメラの回転 public void RotateCamera(double x1, double y1, double x2, double y2) { Vector2D A = new Vector2D(); Vector3D N1 = new Vector3D(); Vector3D N2 = new Vector3D(); Vector3D temp = new Vector3D(); double alpha, beta; float x, y, z; N1.X = Setposition.Y; N1.Y = -Setposition.X; N1.Z = LookatPoint.Z; N1.Normalization(); N2.X = LookatPoint.X; N2.Y = LookatPoint.Y; N2.Z = 1; N2.Normalization(); if (Upward.Z > 0) { A.X = (float)((x2 - x1) / w); A.Y = (float)((y2 - y1) / h); } if (Upward.Z < 0) { A.X = (float)((x1 - x2) / w); A.Y = (float)((y1 - y2) / h); } alpha = 2 * Math.PI * A.Y; beta = 2 * Math.PI * A.X; x = Setposition.X; y = Setposition.Y; z = Setposition.Z; rotatematrix.Set_Rotate_ArbAx(N1, alpha); temp = Setposition * rotatematrix; rotatematrix.Set_Rotate_ArbAx(N2, beta); temp = temp * rotatematrix; SetPosition(temp.X, temp.Y, temp.Z); if (Vector3D.Inner(temp2, Setposition - LookatPoint) > 0 && Upward.Z > 0) Upward.Z = -Upward.Z; if (Vector3D.Inner(temp2, Setposition - LookatPoint) < 0 && Upward.Z < 0) Upward.Z = -Upward.Z; if (Upward.Z > 0) temp2.Set(-Setposition.X, -Setposition.Y, LookatPoint.Z); if (Upward.Z < 0) temp2.Set(Setposition.X, Setposition.Y, LookatPoint.Z); }
//座標を設定 public Vector2D(Vector2D v) { this.Set(v.X, v.Y); }
public static float Inner(Vector2D A, Vector2D B) { return A.X * B.X + A.Y * B.Y; }
//Vector2DをPointF[]に変換 public static PointF[] ToPointF(Vector2D[] A) { PointF[] P = new PointF[A.Length]; for (int i = 0; i < A.Length; i++) { P[i] = A[i].ToPointF(); } return P; }
/// <summary> /// 指定された座標が Edge 上にあるかどうかを判断します。 /// </summary> /// <param name="x">X座標</param> /// <param name="y">Y座標</param> public bool CheckMouseOn(float x, float y) { Vector2D vector1 = new Vector2D(((VertexView)vertex2).GetPosition().X - ((VertexView)vertex1).GetPosition().X, ((VertexView)vertex2).GetPosition().Y - ((VertexView)vertex1).GetPosition().Y); Vector2D vector2 = new Vector2D(x - ((VertexView)vertex1).GetPosition().X, y - ((VertexView)vertex1).GetPosition().Y); if (vector1.Getnorm() < vector2.Getnorm()) return false; vector1.Normalization(); vector2.Normalization(); return (Vector2D.Inner(vector1, vector2) > 0.9999) ? true : false; }
/// <summary> /// 指定された倍率に最適化します。 /// </summary> /// <param name="rate">倍率</param> public void Optimization(float rate) { Vector2D v = new Vector2D(); foreach (VertexView item in vertex) { v.Set(center.X - item.GetPosition().X, center.Y - item.GetPosition().Y); v *= (1 - rate); item.SetPosition(item.GetPosition().X + v.X, item.GetPosition().Y + v.Y); } }
/// <summary> /// Fruchterman-Reingold-Layoutを適用します。 /// </summary> /// <param name="width">描画領域幅</param> /// <param name="height">描画領域高</param> public void Fruchterman_Reingold_Layout(float width, float height) { if (vertexNum == 1) return; Vector2D[] Vpos = new Vector2D[vertexNum]; Vector2D[] Vdisp = new Vector2D[vertexNum]; Vector2D delta = new Vector2D(); float rate = 0.9f; float k = (float)Math.Sqrt((double)(width * rate * height * rate) / vertexNum); float t = 0.1f; float d; for (int i = 0; i < vertexNum; i++) { Vpos[i] = new Vector2D(((VertexView)vertex[i]).GetPosition().X, ((VertexView)vertex[i]).GetPosition().Y); Vdisp[i] = new Vector2D(); } for (int count = 0; count < 50; count++) { for (int i = 0; i < Vpos.Length; i++) { Vdisp[i].Init(); for (int j = 0; j < Vpos.Length; j++) { if (i != j) { delta = Vpos[i] - Vpos[j]; d = delta.Getnorm(); delta.Normalization(); Vdisp[i] += delta * f_r(d, k); } } } for (int i = 0; i < edgeNum; i++) { int n1 = vertex.IndexOf((VertexView)edge[i].GetEdgeVertex(Edge.VERTEX_FIRST)); int n2 = vertex.IndexOf((VertexView)edge[i].GetEdgeVertex(Edge.VERTEX_SECOND)); if (n1 != -1 && n2 != -1) { delta = Vpos[n1] - Vpos[n2]; d = delta.Getnorm(); delta.Normalization(); Vdisp[n1] -= delta * f_a(d, k); Vdisp[n2] += delta * f_a(d, k); } } for (int i = 0; i < Vpos.Length; i++) { d = Vdisp[i].Getnorm(); Vpos[i] += (Vdisp[i] / d) * Math.Min(d, t); Vpos[i].X = (float)Math.Min(width * rate, Math.Max(width * (1 - rate), Vpos[i].X)); Vpos[i].Y = (float)Math.Min(height * rate, Math.Max(height * (1 - rate), Vpos[i].Y)); ((VertexView)vertex[i]).SetPosition(Vpos[i].X, Vpos[i].Y); } } }
/// <summary> /// Spring-Electrical-Layoutを適用します。 /// </summary> /// <param name="width">描画領域幅</param> /// <param name="height">描画領域高</param> public void Spring_Electrical(float width, float height) { Vector2D[] velocity = new Vector2D[vertexNum]; //頂点ごとの速度 Vector2D force = new Vector2D(); //頂点に作用する力 Vector2D delta = new Vector2D(); //差分 float rate = 0.9f; //比率 for (int i = 0; i < vertexNum; i++) { force.Init(); for (int j = 0; j < vertexNum; j++) { if (i != j) { delta.Set(((VertexView)vertex[i]).GetPosition().X - ((VertexView)vertex[j]).GetPosition().X, ((VertexView)vertex[i]).GetPosition().Y - ((VertexView)vertex[j]).GetPosition().Y); force += 500 * delta / (delta.Getnorm() * delta.Getnorm()); } } for (int j = 0; j < edgeNum; j++) { int index; if ((index = edge[j].FindContainIndex(vertex[i])) != -1) { float X1, Y1, X2, Y2; X1 = ((VertexView)vertex[i]).GetPosition().X; Y1 = ((VertexView)vertex[i]).GetPosition().Y; X2 = ((VertexView)edge[j].GetEdgeVertex((index + 1) % 2)).GetPosition().X; Y2 = ((VertexView)edge[j].GetEdgeVertex((index + 1) % 2)).GetPosition().Y; delta.Set(X2 - X1, Y2 - Y1); force += 0.06f * delta; } } velocity[i] = new Vector2D(force.X * 0.85f, force.Y * 0.85f); } for (int i = 0; i < vertexNum; i++) { delta.Set(((VertexView)vertex[i]).GetPosition().X, ((VertexView)vertex[i]).GetPosition().Y); delta += velocity[i]; delta.X = (float)Math.Min(width * rate, Math.Max(width * (1 - rate), delta.X)); delta.Y = (float)Math.Min(height * rate, Math.Max(height * (1 - rate), delta.Y)); ((VertexView)vertex[i]).SetPosition(delta.X, delta.Y); } }