public bool CalculateSurface(SpringMesh sMesh, double thickness, List <Curve> curvesRight, List <Curve> curvesLeft) { foreach (Edge edge in sMesh.Edges) { if (edge.SecondTriangleIndex >= 0) { // first vertex // first triangle #region curve01 int firstPtId = edge.FirstVertexIndex; int firstTriangleIdRight = edge.FirstTriangleIndex; Vertex firstPtVertex = sMesh.Vertices[firstPtId]; double firstPtVertexFactor = vertexFactors[firstPtId]; //Point3d firstTriCentreRight = sMesh.ComputeTriangleCenter(firstTriangleIdRight); Point3d firstTriCentreRight = sMesh.ComputeCircumscribedCircleCenter(firstTriangleIdRight); Vector3d firstNormalRight = thickness * sMesh.ComputeTriangleNormal(firstTriangleIdRight); Point3d firstTriCentreUpRight = firstTriCentreRight + firstNormalRight; // the first control point Point3d firstTriCentreDownRight = firstTriCentreRight - firstNormalRight; // the seventh control point Point3d firstCPt02Right = (firstPtVertexFactor - 0.2) * firstPtVertex.Position + (1 - firstPtVertexFactor + 0.2) * firstTriCentreRight; Point3d firstCPt02UpRight = firstCPt02Right + firstNormalRight; // the second control point Point3d firstCPt02DownRight = firstCPt02Right - firstNormalRight; // the sixth control point Point3d firstCPt03Right = firstPtVertexFactor * firstPtVertex.Position + (1 - firstPtVertexFactor) * firstTriCentreRight; Point3d firstCPt03UpRight = firstCPt03Right + firstNormalRight; // the third control point Point3d firstCPt03DownRight = firstCPt03Right - firstNormalRight; // the fifth control point Point3d firstUpPtRight = firstPtVertex.Position; // the fourth control point List <Point3d> firstControlPointRight = new List <Point3d>() { firstTriCentreUpRight, firstCPt02UpRight, firstCPt03UpRight, firstUpPtRight, firstCPt03DownRight, firstCPt02DownRight, firstTriCentreDownRight }; #endregion NurbsCurve firstNurbCurveRight = NurbsCurve.Create(false, 5, firstControlPointRight); // second triangle #region curve02 int firstTriangleIdLeft = edge.SecondTriangleIndex; //Point3d firstTriCentreLeft = sMesh.ComputeTriangleCenter(firstTriangleIdLeft); Point3d firstTriCentreLeft = sMesh.ComputeCircumscribedCircleCenter(firstTriangleIdLeft); Vector3d firstNormalLeft = thickness * sMesh.ComputeTriangleNormal(firstTriangleIdLeft); Point3d firstTriCentreUpLeft = firstTriCentreLeft + firstNormalLeft; // the first control point Point3d firstTriCentreDownLeft = firstTriCentreLeft - firstNormalLeft; // the seventh control point Point3d firstCPt02Left = (firstPtVertexFactor - 0.2) * firstPtVertex.Position + (1 - firstPtVertexFactor + 0.2) * firstTriCentreLeft; Point3d firstCPt02UpLeft = firstCPt02Left + firstNormalLeft; // the second control point Point3d firstCPt02DownLeft = firstCPt02Left - firstNormalLeft; // the sixth control point Point3d firstCPt03Left = firstPtVertexFactor * firstPtVertex.Position + (1 - firstPtVertexFactor) * firstTriCentreLeft; Point3d firstCPt03UpLeft = firstCPt03Left + firstNormalLeft; // the third control point Point3d firstCPt03DownLeft = firstCPt03Left - firstNormalLeft; // the fifth control point Point3d firstUpPtLeft = firstPtVertex.Position; // the fourth control point List <Point3d> firstControlPointLeft = new List <Point3d>() { firstTriCentreUpLeft, firstCPt02UpLeft, firstCPt03UpLeft, firstUpPtLeft, firstCPt03DownLeft, firstCPt02DownLeft, firstTriCentreDownLeft }; #endregion NurbsCurve firstNurbCurveLeft = NurbsCurve.Create(false, 5, firstControlPointLeft); curvesRight.Add(firstNurbCurveRight); curvesLeft.Add(firstNurbCurveLeft); /* * Brep[] brep1 = Brep.CreateFromLoft( * new List<Curve>() { firstNurbCurveRight, firstNurbCurveLeft }, * Point3d.Unset, Point3d.Unset, LoftType.Developable, false); * * if (brep1.Length > 0) breps.Add(brep1[0]); */ // second vertex // first triangle #region curve03 int secondPtId = edge.SecondVertexIndex; int secondTriangleIdRight = edge.FirstTriangleIndex; Vertex secondPtVertex = sMesh.Vertices[secondPtId]; double secondPtVertexFactor = vertexFactors[secondPtId]; //Point3d secondTriCentreRight = sMesh.ComputeTriangleCenter(secondTriangleIdRight); Point3d secondTriCentreRight = sMesh.ComputeCircumscribedCircleCenter(secondTriangleIdRight); Vector3d secondNormalRight = thickness * sMesh.ComputeTriangleNormal(secondTriangleIdRight); Point3d secondTriCentreUpRight = secondTriCentreRight + secondNormalRight; // the second control point Point3d secondTriCentreDownRight = secondTriCentreRight - secondNormalRight; // the seventh control point Point3d secondCPt02Right = (secondPtVertexFactor - 0.2) * secondPtVertex.Position + (1 - secondPtVertexFactor + 0.2) * secondTriCentreRight; Point3d secondCPt02UpRight = secondCPt02Right + secondNormalRight; // the second control point Point3d secondCPt02DownRight = secondCPt02Right - secondNormalRight; // the sixth control point Point3d secondCPt03Right = secondPtVertexFactor * secondPtVertex.Position + (1 - secondPtVertexFactor) * secondTriCentreRight; Point3d secondCPt03UpRight = secondCPt03Right + secondNormalRight; // the third control point Point3d secondCPt03DownRight = secondCPt03Right - secondNormalRight; // the fifth control point Point3d secondUpPtRight = secondPtVertex.Position; // the fourth control point List <Point3d> secondControlPointRight = new List <Point3d>() { secondTriCentreUpRight, secondCPt02UpRight, secondCPt03UpRight, secondUpPtRight, secondCPt03DownRight, secondCPt02DownRight, secondTriCentreDownRight }; #endregion NurbsCurve secondNurbCurveRight = NurbsCurve.Create(false, 5, secondControlPointRight); // second triangle #region curve04 int secondTriangleIdLeft = edge.SecondTriangleIndex; //Point3d secondTriCentreLeft = sMesh.ComputeTriangleCenter(secondTriangleIdLeft); Point3d secondTriCentreLeft = sMesh.ComputeCircumscribedCircleCenter(secondTriangleIdLeft); Vector3d secondNormalLeft = thickness * sMesh.ComputeTriangleNormal(secondTriangleIdLeft); Point3d secondTriCentreUpLeft = secondTriCentreLeft + secondNormalLeft; // the second control point Point3d secondTriCentreDownLeft = secondTriCentreLeft - secondNormalLeft; // the seventh control point Point3d secondCPt02Left = (secondPtVertexFactor - 0.2) * secondPtVertex.Position + (1 - secondPtVertexFactor + 0.2) * secondTriCentreLeft; Point3d secondCPt02UpLeft = secondCPt02Left + secondNormalLeft; // the second control point Point3d secondCPt02DownLeft = secondCPt02Left - secondNormalLeft; // the sixth control point Point3d secondCPt03Left = secondPtVertexFactor * secondPtVertex.Position + (1 - secondPtVertexFactor) * secondTriCentreLeft; Point3d secondCPt03UpLeft = secondCPt03Left + secondNormalLeft; // the third control point Point3d secondCPt03DownLeft = secondCPt03Left - secondNormalLeft; // the fifth control point Point3d secondUpPtLeft = secondPtVertex.Position; // the fourth control point List <Point3d> secondControlPointLeft = new List <Point3d>() { secondTriCentreUpLeft, secondCPt02UpLeft, secondCPt03UpLeft, secondUpPtLeft, secondCPt03DownLeft, secondCPt02DownLeft, secondTriCentreDownLeft }; #endregion NurbsCurve secondNurbCurveLeft = NurbsCurve.Create(false, 5, secondControlPointLeft); curvesRight.Add(secondNurbCurveRight); curvesLeft.Add(secondNurbCurveLeft); /* * Brep[] brep2 = Brep.CreateFromLoft( * new List<Curve>() { firstNurbCurveRight, firstNurbCurveLeft }, * Point3d.Unset, Point3d.Unset, LoftType.Developable, false); * * if (brep2.Length > 0) breps.Add(brep2[0]); */ } } return(true); }
protected override void SolveInstance(IGH_DataAccess DA) { iPoints = new List <Point3d>(); DA.GetDataList <Point3d>("Points", iPoints); iApicals = new List <Circle>(); DA.GetDataList <Circle>("Apicals", iApicals); iMasses = new List <double>(); DA.GetDataList <double>("Masses", iMasses); DA.GetData <Curve>("Boundary Curve", ref iBoundaryCurve); DA.GetData <double>("Rest Length Scale", ref iRestLengthScale); DA.GetData <double>("Rest Length Offset", ref iRestLengthOffset); DA.GetData <double>("Stiffness", ref iStiffness); DA.GetData <double>("Bending Stiffness", ref iBendingStiffness); DA.GetData <bool>("In/Out Switch", ref iInOutSwitch); DA.GetData <double>("In/Out Threshold", ref iInOutThreshold); DA.GetData <double>("Boundary Vertex Threshold", ref iBoundaryVertexThreshold); iFixedPointExclusion = new List <Curve>(); DA.GetDataList <Curve>("Fixed Point Exclusion", iFixedPointExclusion); iFixedPointInclusion = new List <Curve>(); DA.GetDataList <Curve>("Fixed Point Inclusion", iFixedPointInclusion); // =========================================================================================== // Compute Delaunay Triangulation // =========================================================================================== List <DelaunayVertex> delaunayVertices = new List <DelaunayVertex>(); foreach (Point3d point in iPoints) { delaunayVertices.Add(new DelaunayVertex(point.X, point.Y)); } List <Triad> triads = new DelaunayTriangulator().Triangulation(delaunayVertices); HashSet <Tuple <int, int> > delaunayEdgeTuples = new HashSet <Tuple <int, int> >(); for (int i = 0; i < triads.Count; i++) { Triad triad = triads[i]; delaunayEdgeTuples.Add(triad.a < triad.b ? new Tuple <int, int>(triad.a, triad.b) : new Tuple <int, int>(triad.b, triad.a)); delaunayEdgeTuples.Add(triad.b < triad.c ? new Tuple <int, int>(triad.b, triad.c) : new Tuple <int, int>(triad.c, triad.b)); delaunayEdgeTuples.Add(triad.c < triad.a ? new Tuple <int, int>(triad.c, triad.a) : new Tuple <int, int>(triad.a, triad.c)); } // =========================================================================================== // Convert Delaunay mesh to particle-spring mesh // =========================================================================================== oSpringMesh = new SpringMesh(); Curve boundaryCurveXY = Curve.ProjectToPlane(iBoundaryCurve, Plane.WorldXY); // Create edge list ----------------------------------------------------------------------------------------------- foreach (Tuple <int, int> delaunayEdgeTuple in delaunayEdgeTuples) { Point3d A = iPoints[delaunayEdgeTuple.Item1]; Point3d B = iPoints[delaunayEdgeTuple.Item2]; Point3d M = 0.5 * (A + B); // Skip if the edge lies outside of the boundary double t; boundaryCurveXY.ClosestPoint(M, out t); Point3d N = boundaryCurveXY.PointAt(t); if (Vector3d.CrossProduct(boundaryCurveXY.TangentAt(t), M - N).Z *(iInOutSwitch ? -1.0 : 1.0) < 0.0 && Utils.DistanceSquared(M, N) > iInOutThreshold * iInOutThreshold) { continue; } double edgeLength = Utils.Distance(A, B); double restLength = iRestLengthScale * edgeLength + iRestLengthOffset; oSpringMesh.Edges.Add(new Edge(delaunayEdgeTuple.Item1, delaunayEdgeTuple.Item2, restLength, iStiffness, Math.PI, iBendingStiffness)); } // Create vertex list ----------------------------------------------------------------------------------------------- List <HashSet <int> > neighborVerticesSets = new List <HashSet <int> >(); for (int i = 0; i < iPoints.Count; i++) { neighborVerticesSets.Add(new HashSet <int>()); } foreach (Edge edge in oSpringMesh.Edges) { neighborVerticesSets[edge.FirstVertexIndex].Add(edge.SecondVertexIndex); neighborVerticesSets[edge.SecondVertexIndex].Add(edge.FirstVertexIndex); } for (int i = 0; i < iPoints.Count; i++) { Point3d p = iPoints[i]; double t; boundaryCurveXY.ClosestPoint(p, out t); bool vertexFixedness = false; bool isBoundaryVertex = false; bool isColumnVertex = false; if (Utils.Distance(p, boundaryCurveXY.PointAt(t)) < iBoundaryVertexThreshold) { vertexFixedness = true; isBoundaryVertex = true; } else { foreach (Curve curve in iFixedPointInclusion) { if (curve.Contains(p) == PointContainment.Inside) { vertexFixedness = true; isColumnVertex = true; break; } } } Vertex vertex = new Vertex(p, Vector3d.Zero, neighborVerticesSets[i].ToList <int>(), iMasses.Count == 1 ? iMasses[0] : iMasses[i], vertexFixedness); vertex.IsBoundaryVertex = isBoundaryVertex; vertex.IsColumnVertex = isColumnVertex; oSpringMesh.Vertices.Add(vertex); } // Set boundary edge ----------------------------------------------------------------------------------------------- foreach (Edge edge in oSpringMesh.Edges) { if (oSpringMesh.Vertices[edge.FirstVertexIndex].IsBoundaryVertex && oSpringMesh.Vertices[edge.SecondVertexIndex].IsBoundaryVertex) { edge.IsBoundaryEdge = true; } else if (oSpringMesh.Vertices[edge.FirstVertexIndex].IsColumnVertex && oSpringMesh.Vertices[edge.SecondVertexIndex].IsColumnVertex) { edge.IsColumnEdge = true; } } // Create triangle list ------------------------------------------------------------------------------------------------ Dictionary <Tuple <int, int, int>, int> tripletDict = new Dictionary <Tuple <int, int, int>, int>(); for (int k = 0; k < oSpringMesh.Edges.Count; k++) { Edge edge = oSpringMesh.Edges[k]; Vertex A = oSpringMesh.Vertices[edge.FirstVertexIndex]; Vertex B = oSpringMesh.Vertices[edge.SecondVertexIndex]; for (int i = 0; i < A.NeighborVertexIndices.Count; i++) { for (int j = 0; j < B.NeighborVertexIndices.Count; j++) { if (A.NeighborVertexIndices[i] == B.NeighborVertexIndices[j]) { Tuple <int, int, int> triplet = sortTriplet(edge.FirstVertexIndex, edge.SecondVertexIndex, A.NeighborVertexIndices[i]); if (tripletDict.ContainsKey(triplet)) { if (edge.FirstTriangleIndex < 0) { edge.FirstTriangleIndex = tripletDict[triplet]; edge.FirstAdjacentVertexIndex = A.NeighborVertexIndices[i]; } else { edge.SecondTriangleIndex = tripletDict[triplet]; edge.SecondAdjacentVertexIndex = A.NeighborVertexIndices[i]; } } else { oSpringMesh.Triangles.Add(new Triangle(triplet.Item1, triplet.Item2, triplet.Item3)); int triangleIndex = oSpringMesh.Triangles.Count - 1; if (edge.FirstTriangleIndex < 0) { edge.FirstTriangleIndex = triangleIndex; edge.FirstAdjacentVertexIndex = A.NeighborVertexIndices[i]; } else { edge.SecondTriangleIndex = triangleIndex; edge.SecondAdjacentVertexIndex = A.NeighborVertexIndices[i]; } tripletDict.Add(triplet, triangleIndex); } } } } } // =========================================================================================== // Compute edge indices for each triangle // =========================================================================================== for (int i = 0; i < oSpringMesh.Edges.Count; i++) { Edge edge = oSpringMesh.Edges[i]; Triangle triangle = oSpringMesh.Triangles[edge.FirstTriangleIndex]; if (triangle.FirstEdgeIndex == -1) { triangle.FirstEdgeIndex = i; } else if (triangle.SecondEdgeIndex == -1) { triangle.SecondEdgeIndex = i; } else { triangle.ThirdEdgeIndex = i; } if (edge.SecondTriangleIndex == -1) { continue; } triangle = oSpringMesh.Triangles[edge.SecondTriangleIndex]; if (triangle.FirstEdgeIndex == -1) { triangle.FirstEdgeIndex = i; } else if (triangle.SecondEdgeIndex == -1) { triangle.SecondEdgeIndex = i; } else { triangle.ThirdEdgeIndex = i; } } // =========================================================================================== // Rearange the vertex order in each triangle so the normal calculation is consistent // =========================================================================================== for (int i = 0; i < oSpringMesh.Triangles.Count; i++) { if (oSpringMesh.ComputeTriangleNormal(i).Z < 0.0) { int temp = oSpringMesh.Triangles[i].SecondVertexIndex; oSpringMesh.Triangles[i].SecondVertexIndex = oSpringMesh.Triangles[i].ThirdVertexIndex; oSpringMesh.Triangles[i].ThirdVertexIndex = temp; } } // =========================================================================================== // Rearranging edge adjacent vertex indices for consitency // =========================================================================================== foreach (Edge edge in oSpringMesh.Edges) { if (edge.SecondAdjacentVertexIndex == -1) { Point3d A = oSpringMesh.Vertices[edge.FirstVertexIndex].Position; Point3d B = oSpringMesh.Vertices[edge.SecondVertexIndex].Position; Point3d M = oSpringMesh.Vertices[edge.FirstAdjacentVertexIndex].Position; if (Vector3d.CrossProduct(B - A, M - A) * oSpringMesh.ComputeTriangleNormal(edge.FirstTriangleIndex) < 0.0) { Point3d temp = A; A = B; B = temp; } } else { Point3d A = oSpringMesh.Vertices[edge.FirstVertexIndex].Position; Point3d B = oSpringMesh.Vertices[edge.SecondVertexIndex].Position; Point3d M = oSpringMesh.Vertices[edge.FirstAdjacentVertexIndex].Position; Point3d N = oSpringMesh.Vertices[edge.SecondAdjacentVertexIndex].Position; if (Vector3d.CrossProduct(B - A, M - A) * oSpringMesh.ComputeTriangleNormal(edge.FirstAdjacentVertexIndex) < 0.0) { int temp = edge.FirstAdjacentVertexIndex; edge.FirstAdjacentVertexIndex = edge.SecondAdjacentVertexIndex; edge.SecondAdjacentVertexIndex = temp; temp = edge.FirstTriangleIndex; edge.FirstTriangleIndex = edge.SecondTriangleIndex; edge.SecondTriangleIndex = temp; } } } // =========================================================================================== // Compute adjacent vertex index for each triangle // =========================================================================================== //foreach (Triangle triangle in oSpringMesh.Triangles) //{ // Vertex firstVertex = oSpringMesh.Vertices[triangle.FirstVertexIndex]; // Vertex secondVertex = oSpringMesh.Vertices[triangle.SecondVertexIndex]; // Vertex thirdVertex = oSpringMesh.Vertices[triangle.ThirdVertexIndex]; // foreach (int firstNeighbourIndex in firstVertex.NeighborVertexIndices) // foreach (int secondNeighbourIndex in secondVertex.NeighborVertexIndices) // if (firstNeighbourIndex == secondNeighbourIndex && firstNeighbourIndex != triangle.ThirdVertexIndex) // triangle.FirstSecondAdjacentVertexIndex = firstNeighbourIndex; // foreach (int secondNeighbourIndex in secondVertex.NeighborVertexIndices) // foreach (int thirdNeighbourIndex in thirdVertex.NeighborVertexIndices) // if (secondNeighbourIndex == thirdNeighbourIndex && secondNeighbourIndex != triangle.FirstVertexIndex) // triangle.SecondThirdAdjacentVertexIndex = secondNeighbourIndex; // foreach (int thirdNeighbourIndex in thirdVertex.NeighborVertexIndices) // foreach (int firstNeighbourIndex in firstVertex.NeighborVertexIndices) // if (thirdNeighbourIndex == firstNeighbourIndex && thirdNeighbourIndex != triangle.SecondVertexIndex) // triangle.ThirdFirstAdjacentVertexIndex = thirdNeighbourIndex; //} // =========================================================================================== // 3D Boundary Curve // =========================================================================================== //Brep brep = Brep.CreatePatch(new List<GeometryBase>() { iBoundaryCurve }, null, DocumentTolerance()); //DA.SetDataList(2, new List<Brep>() { brep }); foreach (Vertex vertex in oSpringMesh.Vertices) { if (vertex.IsBoundaryVertex) { double t; boundaryCurveXY.ClosestPoint(vertex.Position, out t); Plane frame; boundaryCurveXY.PerpendicularFrameAt(t, out frame); CurveIntersections curveInteresections = Intersection.CurvePlane(iBoundaryCurve, frame, DocumentTolerance()); Point3d intersection = Point3d.Unset; double minDist = 999999.0; for (int i = 0; i < curveInteresections.Count; i++) { double d = vertex.Position.DistanceTo(curveInteresections[i].PointA); if (d < minDist) { minDist = d; intersection = curveInteresections[i].PointA; } } vertex.Position = intersection; } else { //LineCurve lineCurve = new LineCurve( // new Point3d(vertex.Position.X, vertex.Position.Y, vertex.Position.Z - 10.0), // new Point3d(vertex.Position.X, vertex.Position.Y, vertex.Position.Z + 10.0) // ); //Curve[] overlapCurves; //Point3d[] intersectionPoints; //Intersection.CurveBrep(lineCurve, brep, DocumentTolerance(), out overlapCurves, out intersectionPoints); //if (intersectionPoints.Length > 0) // vertex.Position = intersectionPoints[0]; } } // =========================================================================================== // Initial curving bias // =========================================================================================== DA.GetData <double>("Initial Curving Bias", ref iInitialCurvingBias); DA.GetData <bool>("Bias Apical Regions", ref iBiasApicalRegion); foreach (Vertex vertex in oSpringMesh.Vertices) { if (vertex.IsBoundaryVertex || vertex.IsFixed) { continue; } vertex.Position.Z = computeBiasHeight(vertex.Position, iBiasApicalRegion, boundaryCurveXY); } // =========================================================================================== // Conclusion // =========================================================================================== foreach (Edge edge in oSpringMesh.Edges) { oDebugCurves1.Add(new LineCurve(oSpringMesh.Vertices[edge.FirstVertexIndex].Position, oSpringMesh.Vertices[edge.SecondVertexIndex].Position)); } DA.SetData(0, oInfo); DA.SetDataList(1, oDebugCurves1); DA.SetData(6, oSpringMesh); }