/// <summary> /// Get unit normal vector, average of vertice noraml /// </summary> /// <param name="f">A face index</param> /// <returns>Unit normal vector</returns> public PlanktonXYZ GetFaceNormal(int f) { // Gene Added function PlanktonXYZ normal = PlanktonXYZ.Zero; foreach (int i in this.GetFaceVertices(f)) { normal += _mesh.Vertices.GetNormal(i); } normal *= 1f / normal.Length; //!!!!!!!!!!!!!!!!! plankton normal have bugs!!!!!!! //int[] fV = this.GetFaceVertices(f); //if (fV.Length == 4) //{ // PlanktonXYZ v1 = _mesh.Vertices[2].ToXYZ() - _mesh.Vertices[0].ToXYZ(); // PlanktonXYZ v2 = _mesh.Vertices[3].ToXYZ() - _mesh.Vertices[1].ToXYZ(); // normal += PlanktonXYZ.CrossProduct(v2, v1); //} //if (fV.Length == 3) //{ // PlanktonXYZ v1 = _mesh.Vertices[2].ToXYZ() - _mesh.Vertices[0].ToXYZ(); // PlanktonXYZ v2 = _mesh.Vertices[1].ToXYZ() - _mesh.Vertices[0].ToXYZ(); // normal += PlanktonXYZ.CrossProduct(v2, v1); //} return(normal); }
/// <summary> /// Gets the barycenter of a face's vertices. /// </summary> /// <param name="f">A face index.</param> /// <returns>The location of the specified face's barycenter.</returns> public PlanktonXYZ GetFaceCenter(int f) { PlanktonXYZ centroid = PlanktonXYZ.Zero; int count = 0; foreach (int i in this.GetFaceVertices(f)) { centroid += _mesh.Vertices[i].ToXYZ(); count++; } centroid *= 1f / count; return(centroid); }
public double GetLength(int index) /// <summary> /// Measure the length of a single halfedge /// </summary> /// <returns>The length of the halfedge, or -1 if unused</returns> { double EdgeLength = -1; if (this[index].IsUnused == false) { PlanktonXYZ Start = _mesh.Vertices[this[index].StartVertex].ToXYZ(); PlanktonXYZ End = _mesh.Vertices[this.EndVertex(index)].ToXYZ(); EdgeLength = (End - Start).Length; } return(EdgeLength); }
/// <summary> /// Calculate the volume of the mesh /// </summary> public double Volume() { double VolumeSum = 0; for (int i = 0; i < this.Faces.Count; i++) { int[] FaceVerts = this.Faces.GetFaceVertices(i); int EdgeCount = FaceVerts.Length; if (EdgeCount == 3) { PlanktonXYZ P = this.Vertices[FaceVerts[0]].ToXYZ(); PlanktonXYZ Q = this.Vertices[FaceVerts[1]].ToXYZ(); PlanktonXYZ R = this.Vertices[FaceVerts[2]].ToXYZ(); //get the signed volume of the tetrahedron formed by the triangle and the origin VolumeSum += (1 / 6d) * ( P.X * Q.Y * R.Z + P.Y * Q.Z * R.X + P.Z * Q.X * R.Y - P.X * Q.Z * R.Y - P.Y * Q.X * R.Z - P.Z * Q.Y * R.X); } else { PlanktonXYZ P = this._faces.GetFaceCenter(i); for (int j = 0; j < EdgeCount; j++) { PlanktonXYZ Q = this.Vertices[FaceVerts[j]].ToXYZ(); PlanktonXYZ R = this.Vertices[FaceVerts[(j + 1) % EdgeCount]].ToXYZ(); VolumeSum += (1 / 6d) * ( P.X * Q.Y * R.Z + P.Y * Q.Z * R.X + P.Z * Q.X * R.Y - P.X * Q.Z * R.Y - P.Y * Q.X * R.Z - P.Z * Q.Y * R.X); } } } return(VolumeSum); }
/// <summary> /// Gets the normal vector at a vertex. /// </summary> /// <param name="index">The index of a vertex.</param> /// <returns>The area weighted vertex normal.</returns> public PlanktonXYZ GetNormal(int index) { PlanktonXYZ vertex = this[index].ToXYZ(); PlanktonXYZ normal = new PlanktonXYZ(); var ring = this.GetVertexNeighbours(index); int n = ring.Length; for (int i = 0; i < n - 1; i++) { normal += PlanktonXYZ.CrossProduct( this[ring[i]].ToXYZ() - vertex, this[ring[i + 1]].ToXYZ() - vertex); } if (this.IsBoundary(index) == false) { normal += PlanktonXYZ.CrossProduct( this[n - 1].ToXYZ() - vertex, this[0].ToXYZ() - vertex); } return(normal * (-1.0f / normal.Length)); // return unit vector }
public static float DistanceTo(PlanktonXYZ v1, PlanktonXYZ v2) { float dx = v1.X - v2.X; float dy = v1.Y - v2.Y; float dz = v1.Z - v2.Z; return (float)Math.Sqrt(dx * dx + dy * dy + dz * dz); }
/// <summary> /// Computes the cross product (or vector product, or exterior product) of two vectors. /// <para>This operation is not commutative.</para> /// </summary> /// <param name="a">First vector.</param> /// <param name="b">Second vector.</param> /// <returns>A new vector that is perpendicular to both a and b, /// <para>has Length == a.Length * b.Length and</para> /// <para>with a result that is oriented following the right hand rule.</para> /// </returns> public static PlanktonXYZ CrossProduct(PlanktonXYZ a, PlanktonXYZ b) { return new PlanktonXYZ(a._y * b._z - b._y * a._z, a._z * b._x - b._z * a._x, a._x * b._y - b._x * a._y); }
/// <summary> /// Determines whether the specified vector has the same values as the present vector. /// </summary> /// <param name="vector">The specified vector.</param> /// <returns>true if vector has the same components as this; otherwise false.</returns> public bool Equals(PlanktonXYZ vector) { return(this == vector); }
/// <summary> /// Computes the cross product (or vector product, or exterior product) of two vectors. /// <para>This operation is not commutative.</para> /// </summary> /// <param name="a">First vector.</param> /// <param name="b">Second vector.</param> /// <returns>A new vector that is perpendicular to both a and b, /// <para>has Length == a.Length * b.Length and</para> /// <para>with a result that is oriented following the right hand rule.</para> /// </returns> public static PlanktonXYZ CrossProduct(PlanktonXYZ a, PlanktonXYZ b) { return(new PlanktonXYZ(a._y * b._z - b._y * a._z, a._z * b._x - b._z * a._x, a._x * b._y - b._x * a._y)); }
public PlanktonLine(float x0, float y0, float z0, float x1, float y1, float z1) { this.m_from = new PlanktonXYZ(x0, y0, z0); this.m_to = new PlanktonXYZ(x1, y1, z1); }
public PlanktonMesh Dual(int option) // Gene hacked, 0: barycenter, 1: circumcenter { // hack for open meshes // TODO: improve this ugly method if (this.IsClosed() == false) { var dual = new PlanktonMesh(); // create vertices from face centers for (int i = 0; i < this.Faces.Count; i++) { // Gene added options if (option == 0) { dual.Vertices.Add(this.Faces.GetFaceCenter(i)); } else if (option == 1) { dual.Vertices.Add(this.Faces.GetFaceCircumCenter(i)); } } // create faces from the adjacent face indices of non-boundary vertices for (int i = 0; i < this.Vertices.Count; i++) { if (this.Vertices.IsBoundary(i)) { continue; } dual.Faces.AddFace(this.Vertices.GetVertexFaces(i)); } return(dual); } // can later add options for other ways of defining face centres (barycenter/circumcenter etc) // won't work yet with naked boundaries PlanktonMesh P = this; PlanktonMesh D = new PlanktonMesh(); //for every primal face, add the barycenter to the dual's vertex list //dual vertex outgoing HE is primal face's start HE //for every vertex of the primal, add a face to the dual //dual face's startHE is primal vertex's outgoing's pair for (int i = 0; i < P.Faces.Count; i++) { // Gene added circumcenter option PlanktonXYZ fc = new PlanktonXYZ(); // face center if (option == 0) { fc = P.Faces.GetFaceCenter(i); } else if (option == 1) { fc = P.Faces.GetFaceCircumCenter(i); } D.Vertices.Add(new PlanktonVertex(fc.X, fc.Y, fc.Z)); // //D.Vertices.Add(new PlanktonVertex(fc.X, fc.Y, fc.Z)); // gene deleted int[] FaceHalfedges = P.Faces.GetHalfedges(i); for (int j = 0; j < FaceHalfedges.Length; j++) { if (P.Halfedges[P.Halfedges.GetPairHalfedge(FaceHalfedges[j])].AdjacentFace != -1) { // D.Vertices[i].OutgoingHalfedge = FaceHalfedges[j]; D.Vertices[D.Vertices.Count - 1].OutgoingHalfedge = P.Halfedges.GetPairHalfedge(FaceHalfedges[j]); break; } } } for (int i = 0; i < P.Vertices.Count; i++) { if (P.Vertices.NakedEdgeCount(i) == 0) { int df = D.Faces.Add(PlanktonFace.Unset); // D.Faces[i].FirstHalfedge = P.PairHalfedge(P.Vertices[i].OutgoingHalfedge); D.Faces[df].FirstHalfedge = P.Vertices[i].OutgoingHalfedge; } } // dual halfedge start V is primal AdjacentFace // dual halfedge AdjacentFace is primal end V // dual nextHE is primal's pair's prev // dual prevHE is primal's next's pair // halfedge pairs stay the same for (int i = 0; i < P.Halfedges.Count; i++) { if ((P.Halfedges[i].AdjacentFace != -1) & (P.Halfedges[P.Halfedges.GetPairHalfedge(i)].AdjacentFace != -1)) { PlanktonHalfedge DualHE = PlanktonHalfedge.Unset; PlanktonHalfedge PrimalHE = P.Halfedges[i]; //DualHE.StartVertex = PrimalHE.AdjacentFace; DualHE.StartVertex = P.Halfedges[P.Halfedges.GetPairHalfedge(i)].AdjacentFace; if (P.Vertices.NakedEdgeCount(PrimalHE.StartVertex) == 0) { //DualHE.AdjacentFace = P.Halfedges[P.PairHalfedge(i)].StartVertex; DualHE.AdjacentFace = PrimalHE.StartVertex; } else { DualHE.AdjacentFace = -1; } //This will currently fail with open meshes... //one option could be to build the dual with all halfedges, but mark some as dead //if they connect to vertex -1 //mark the 'external' faces all as -1 (the ones that are dual to boundary verts) //then go through and if any next or prevs are dead hes then replace them with the next one around //this needs to be done repeatedly until no further change //DualHE.NextHalfedge = P.Halfedges[P.PairHalfedge(i)].PrevHalfedge; DualHE.NextHalfedge = P.Halfedges.GetPairHalfedge(PrimalHE.PrevHalfedge); //DualHE.PrevHalfedge = P.PairHalfedge(PrimalHE.NextHalfedge); DualHE.PrevHalfedge = P.Halfedges[P.Halfedges.GetPairHalfedge(i)].NextHalfedge; D.Halfedges.Add(DualHE); } } return(D); }
public PlanktonXYZ(PlanktonXYZ p) { _x = p.X; _y = p.Y; _z = p.Z; }
public PlanktonXYZ ClosestPoint(PlanktonXYZ testPoint, bool limitToFiniteSegment) { float num = this.ClosestParameter(testPoint); if (limitToFiniteSegment) { num = Math.Min(Math.Max(num, 0f), 1f); } return this.PointAt(num); }
public float DistanceTo(PlanktonXYZ testPoint, bool limitToFiniteSegment) { return this.ClosestPoint(testPoint, limitToFiniteSegment).DistanceTo(testPoint); }
/// <summary> /// Creates a Rhino Vector3f from a Plankton vector. /// </summary> /// <param name="vector">A Plankton vector.</param> /// <returns>A Vector3f with the same XYZ components as the vector.</returns> public static Vector3f ToVector3f(this PlanktonXYZ vector) { return(new Vector3f(vector.X, vector.Y, vector.Z)); }
/// <summary> /// Creates a Rhino Point3d from a Plankton vector. /// </summary> /// <param name="vector">A Plankton vector.</param> /// <returns>A Point3d with the same XYZ components as the vector.</returns> public static Point3d ToPoint3d(this PlanktonXYZ vector) { return(new Point3d(vector.X, vector.Y, vector.Z)); }
public PlanktonMesh MeshFromPoints(PlanktonXYZ p1, PlanktonXYZ p2, PlanktonXYZ p3) { PlanktonMesh mesh = new PlanktonMesh(); mesh.Vertices.Add(p1); mesh.Vertices.Add(p2); mesh.Vertices.Add(p3); mesh.Faces.AddFace(0, 1, 2); return mesh; }
private bool ClosestPointTo(PlanktonXYZ point, ref float t) { bool rc = false; PlanktonXYZ D = m_to - m_from; float DoD = (D.X * D.X + D.Y * D.Y + D.Z * D.Z); if (DoD > 0f) { if (point.DistanceTo(m_from) <= point.DistanceTo(m_to)) { t = ((point - m_from) * D) / DoD; } else { t = 1f + ((point - m_to) * D) / DoD; } rc = true; } return rc; }
public float MinimumDistanceTo(PlanktonXYZ P) { float d = 0, t = 0; if (ClosestPointTo(P, ref t)) { if (t < 0f) t = 0f; else if (t > 1f) t = 1f; d = PointAt(t).DistanceTo(P); } else { // degenerate line d = m_from.DistanceTo(P); t = m_to.DistanceTo(P); if (t < d) d = t; } return d; }
public float DistanceTo(PlanktonXYZ p) { float dx = this.X - p.X; float dy = this.Y - p.Y; float dz = this.Z - p.Z; return (float)Math.Sqrt(dx * dx + dy * dy + dz * dz); }
/// <summary> /// Determines whether the specified vector has the same values as the present vector. /// </summary> /// <param name="vector">The specified vector.</param> /// <returns>true if vector has the same components as this; otherwise false.</returns> public bool Equals(PlanktonXYZ vector) { return this == vector; }
public PlanktonLine(PlanktonXYZ from, PlanktonXYZ to) { this.m_from = from; this.m_to = to; }
public PlanktonMesh CatmullClark(int iteration, List <int> fixVertices, List <int> fixEdges, List <int> fixFaces) { // Gene added catmull clark subdivision function, function written for Leopard. // maybe change this function to static, so can be easier. PlanktonMesh cMesh = new PlanktonMesh(this); // this iteration List <bool> isBoundaryVertices = new List <bool>(); // assign boundary vertices for (int i = 0; i < cMesh.Vertices.Count; i++) { if (cMesh.Vertices.IsBoundary(i)) { isBoundaryVertices.Add(true); } else { isBoundaryVertices.Add(false); } } // set vertices foreach (int v in fixVertices) { isBoundaryVertices[v] = true; } // set edges foreach (int e in fixEdges) { int id = e * 2; //int[] pEndsIndices = cMesh.Halfedges.GetVertices(edge); int pairIndex = cMesh.Halfedges.GetPairHalfedge(id); if (pairIndex < id) { int temp = id; id = pairIndex; pairIndex = temp; } int[] vts = cMesh.Halfedges.GetVertices(id); isBoundaryVertices[vts[0]] = true; isBoundaryVertices[vts[1]] = true; } // set face foreach (int f in fixFaces) { foreach (int v in cMesh.Faces.GetFaceVertices(f)) { isBoundaryVertices[v] = true; } } for (int iter = 0; iter < iteration; iter++) { PlanktonMesh subdMesh = new PlanktonMesh(); // current mesh for each iteration // add the original vertices for (int i = 0; i < cMesh.Vertices.Count; i++) { subdMesh.Vertices.Add(cMesh.Vertices[i].ToXYZ()); } // face centers #region face centers PlanktonXYZ[] faceCenter = new PlanktonXYZ[cMesh.Faces.Count]; for (int i = 0; i < cMesh.Faces.Count; i++) { faceCenter[i] = cMesh.Faces.GetFaceCenter(i); isBoundaryVertices.Add(false); subdMesh.Vertices.Add(cMesh.Faces.GetFaceCenter(i)); } #endregion // new edge points #region new edge points PlanktonXYZ[] newEdgePoints = new PlanktonXYZ[cMesh.Halfedges.Count / 2]; // pair half edges belong to one. for (int i = 0; i < cMesh.Halfedges.Count; i++) { if (i % 2 == 1) { continue; } int pairIndex = cMesh.Halfedges.GetPairHalfedge(i); int[] pEndsIndices = cMesh.Halfedges.GetVertices(i); int fA = cMesh.Halfedges[i].AdjacentFace; int fB = cMesh.Halfedges[pairIndex].AdjacentFace; PlanktonXYZ pStart, pEnd, fAC, fBC; // not boudary condition if (pEndsIndices[0] >= 0 && pEndsIndices[1] >= 0 && fA != -1 && fB != -1) { pStart = cMesh.Vertices[pEndsIndices[0]].ToXYZ(); pEnd = cMesh.Vertices[pEndsIndices[1]].ToXYZ(); fAC = faceCenter[fA]; fBC = faceCenter[fB]; if (isBoundaryVertices[pEndsIndices[0]] && isBoundaryVertices[pEndsIndices[1]]) { newEdgePoints[(int)i / 2] = (cMesh.Vertices[pEndsIndices[0]].ToXYZ() + cMesh.Vertices[pEndsIndices[1]].ToXYZ()) * 0.5f; isBoundaryVertices.Add(true); subdMesh.Vertices.Add(newEdgePoints[(int)i / 2]); } else if ((!isBoundaryVertices[pEndsIndices[0]] && isBoundaryVertices[pEndsIndices[1]]) || (isBoundaryVertices[pEndsIndices[0]] && !isBoundaryVertices[pEndsIndices[1]])) { newEdgePoints[(int)i / 2] = (cMesh.Vertices[pEndsIndices[0]].ToXYZ() + cMesh.Vertices[pEndsIndices[1]].ToXYZ()) * 0.5f * 0.5f + (pStart + pEnd + fAC + fBC) * 0.25f * 0.5f; isBoundaryVertices.Add(false); subdMesh.Vertices.Add(newEdgePoints[(int)i / 2]); } else { newEdgePoints[(int)i / 2] = (pStart + pEnd + fAC + fBC) * 0.25f; isBoundaryVertices.Add(false); subdMesh.Vertices.Add(newEdgePoints[(int)i / 2]); } } // boudary condition else { newEdgePoints[(int)i / 2] = (cMesh.Vertices[pEndsIndices[0]].ToXYZ() + cMesh.Vertices[pEndsIndices[1]].ToXYZ()) * 0.5f; isBoundaryVertices.Add(true); subdMesh.Vertices.Add(newEdgePoints[(int)i / 2]); } } #endregion // new vertex points #region new vertex points PlanktonXYZ[] newVertexPoints = new PlanktonXYZ[cMesh.Vertices.Count]; for (int i = 0; i < cMesh.Vertices.Count; i++) { int n = cMesh.Vertices.GetValence(i); // F int[] fIndices = cMesh.Vertices.GetVertexFaces(i); PlanktonXYZ fn = new PlanktonXYZ(); foreach (int f in fIndices) { if (f != -1) { fn += faceCenter[f]; } } fn *= (float)(1.0f / (n * n)); // E int[] vnIndices = cMesh.Vertices.GetVertexNeighbours(i); PlanktonXYZ vn = new PlanktonXYZ(); foreach (int e in vnIndices) { if (e != -1) { vn += cMesh.Vertices[e].ToXYZ(); } } vn *= (float)(1.0f / (n * n)); // V PlanktonXYZ v = cMesh.Vertices[i].ToXYZ() * (n - 2) * (1.0f / n); if (!isBoundaryVertices[i]) { newVertexPoints[i] = fn + vn + v; subdMesh.Vertices.SetVertex(i, newVertexPoints[i].X, newVertexPoints[i].Y, newVertexPoints[i].Z); } else { newVertexPoints[i] = cMesh.Vertices[i].ToXYZ(); subdMesh.Vertices.SetVertex(i, newVertexPoints[i].X, newVertexPoints[i].Y, newVertexPoints[i].Z); } } #endregion // add mesh face #region construct mesh for (int i = 0; i < cMesh.Faces.Count; i++) { int pMVC = cMesh.Vertices.Count; int fNewID = i + pMVC; int[] fVertices = cMesh.Faces.GetFaceVertices(i); int[] fEdgePts = cMesh.Faces.GetHalfedges(i); int fNum = cMesh.Faces.Count; int eNum = cMesh.Halfedges.Count / 2; if (fVertices.Length == 3) { subdMesh.Faces.AddFace(fNewID, fNum + fEdgePts[0] / 2 + pMVC, fVertices[1], fNum + fEdgePts[1] / 2 + pMVC); subdMesh.Faces.AddFace(fNewID, fNum + fEdgePts[1] / 2 + pMVC, fVertices[2], fNum + fEdgePts[2] / 2 + pMVC); subdMesh.Faces.AddFace(fNewID, fNum + fEdgePts[2] / 2 + pMVC, fVertices[0], fNum + fEdgePts[0] / 2 + pMVC); } else { subdMesh.Faces.AddFace(fNewID, fNum + fEdgePts[0] / 2 + pMVC, fVertices[1], fNum + fEdgePts[1] / 2 + pMVC); subdMesh.Faces.AddFace(fNewID, fNum + fEdgePts[1] / 2 + pMVC, fVertices[2], fNum + fEdgePts[2] / 2 + pMVC); subdMesh.Faces.AddFace(fNewID, fNum + fEdgePts[2] / 2 + pMVC, fVertices[3], fNum + fEdgePts[3] / 2 + pMVC); subdMesh.Faces.AddFace(fNewID, fNum + fEdgePts[3] / 2 + pMVC, fVertices[0], fNum + fEdgePts[0] / 2 + pMVC); } } #endregion cMesh = subdMesh; } return(cMesh); }
/// <summary> /// Adds a new vertex to the end of the Vertex list. /// </summary> /// <param name="vertex">Vertex to add.</param> /// <returns>The index of the newly added vertex.</returns> internal int Add(PlanktonXYZ vertex) { this._list.Add(new PlanktonVertex(vertex.X, vertex.Y, vertex.Z)); return(this.Count - 1); }
public float ClosestParameter(PlanktonXYZ point) { float t = 0; PlanktonXYZ D = m_to - m_from; float DoD = (D.X * D.X + D.Y * D.Y + D.Z * D.Z); if (DoD > 0f) { if (point.DistanceTo(m_from) <= point.DistanceTo(m_to)) { t = ((point - m_from) * D) / DoD; } else { t = 1f + ((point - m_to) * D) / DoD; } } else { t = 0f; } return t; }
public float MaximumDistanceTo(PlanktonXYZ P) { float a, b; a = m_from.DistanceTo(P); b = m_to.DistanceTo(P); return ((a < b) ? b : a); }