/// <summary> /// Geometry - vertex to edges connectivity /// </summary> /// <param name="mesh"></param> /// <returns></returns> public static Line[][] VE_Ln(this Mesh mesh) { Line[][] veSorted_Ln = new Line[mesh.TopologyVertices.Count][]; int[][] veSorted = mesh.VE(); for (int i = 0; i < mesh.TopologyVertices.Count; i++) { veSorted_Ln[i] = new Line[veSorted[i].Length]; for (int j = 0; j < veSorted[i].Length; j++) { Rhino.IndexPair pair = mesh.TopologyEdges.GetTopologyVertices(veSorted[i][j]); int a = -1; int b = -1; if (pair.I == i) { a = pair.I; b = pair.J; } else { b = pair.I; a = pair.J; } veSorted_Ln[i][j] = new Line(mesh.TopologyVertices[a], mesh.TopologyVertices[b]); } } return(veSorted_Ln); }
protected override void SolveInstance(IGH_DataAccess DA) { Mesh mesh = new Mesh(); DA.GetData(0, ref mesh); int iteration = DA.Iteration; int[][] tv = mesh.GetNGonsTopoBoundaries(); HashSet <int> e = mesh.GetAllNGonEdges(tv); Line[] lines = mesh.GetAllNGonEdgesLines(e); bool[] n = mesh.NakedNGonEdges(e); List <Line> linesNaked = new List <Line>(); List <Vector3d> vecs = new List <Vector3d>(); int j = 0; foreach (int i in e) { Line l = mesh.TopologyEdges.EdgeLine(i); //l.Transform(Transform.Rotation()) Rhino.IndexPair ip = mesh.TopologyEdges.GetTopologyVertices(i); int v0 = mesh.TopologyVertices.MeshVertexIndices(ip.I)[0]; int v1 = mesh.TopologyVertices.MeshVertexIndices(ip.J)[0]; Vector3d vec = new Vector3d( (mesh.Normals[v0].X + mesh.Normals[v1].X) * 0.5, (mesh.Normals[v0].Y + mesh.Normals[v1].Y) * 0.5, (mesh.Normals[v0].Z + mesh.Normals[v1].Z) * 0.5 ); vecs.Add(vec); if (n[j]) { linesNaked.Add(l); } j++; } this.PreparePreview(mesh, DA.Iteration, null, false, null, lines.ToList()); DA.SetDataTree(0, new DataTree <Line>(lines, new GH_Path(iteration))); DA.SetDataTree(1, new DataTree <int>(e, new GH_Path(iteration))); DA.SetDataTree(2, new DataTree <bool>(n, new GH_Path(iteration))); DA.SetDataTree(3, new DataTree <Vector3d>(vecs, new GH_Path(iteration))); Line[] ae = new Line[mesh.TopologyEdges.Count]; for (int i = 0; i < mesh.TopologyEdges.Count; i++) { ae[i] = mesh.TopologyEdges.EdgeLine(i); } DA.SetDataTree(4, new DataTree <Line>(linesNaked, new GH_Path(iteration))); DA.SetDataTree(5, new DataTree <Line>(ae, new GH_Path(iteration))); }
//Get ngon planes public static Plane[][] EPlanes(Mesh mesh, HashSet <int> allE, Dictionary <int, int> allEDict, Plane[] planesO, Plane[] planesOffset, int[][] eNgons, double jointWidth, double rotation, Line[] innerLines, int[][] ngonEdges, int[][] jointTypes, int[][] vertexNGons, int[] allV, double maxLength) { Line[] eLine = mesh.GetAllNGonEdgesLines(allE);//Plane origin points will be on those lines Plane[][] mp; //EDGE PLANES Plane[] edgePlanes = new Plane[allEDict.Count]; //Loop through all bisector edge faces and check if that edge belongs to one of edge faces //Dictionary<int, Plane> bisectors = GetBisectors(allE, planesO, eNgons); Dictionary <int, Plane> bisectors = GetCustomAveragePlanes(allE, planesO, eNgons, allV, mesh, ngonEdges, allEDict); for (int i = 0; i < allEDict.Count; i++) { Plane planeForXAxisRotation = (jointTypes[i][0] == 3) ? planesO[eNgons[i][0]] : planesO[eNgons[i][1]]; // Check which edges are connected with bisectors edgePlanes[i] = PlaneUtil.PlaneFromLinePlane(innerLines[i], planeForXAxisRotation); //Take edge vector and rotate it by male plane and in this way get edgePlane foreach (KeyValuePair <int, Plane> pair in bisectors) { //Test if edge is connected to bisector edge //Get connected ngons of bisector edge //Insertion direction: //1. Bisector plane 2Dof insertion freedom //To insert all edges correctly - insertion direction is limited to 1 Dof //2. It is a bisector of mesh faces connected to edge vertices, excluding faces connected to edges int[] bisectorNgons = eNgons[pair.Key]; bool flag1 = eNgons[i].Contains(bisectorNgons[0]); bool flag2 = eNgons[i].Contains(bisectorNgons[1]); if (flag1 || flag2) { Plane modifiedBisectorPlane = new Plane(edgePlanes[i].Origin, pair.Value.XAxis, pair.Value.YAxis); //Move bisector plane to the middle of edge Rhino.IndexPair ip = mesh.TopologyEdges.GetTopologyVertices(allE.ElementAt(i)); Rhino.IndexPair bip = mesh.TopologyEdges.GetTopologyVertices(allE.ElementAt(pair.Key)); //If edge is connected to bisector edge if ((ip.I == bip.I || ip.I == bip.J || ip.J == bip.I || ip.J == bip.J) && (i != pair.Key)) { edgePlanes[i] = PlaneUtil.AlignPlane(edgePlanes[i], modifiedBisectorPlane); //edgePlanes[i] = modifiedBisectorPlane; } else { planeForXAxisRotation = (jointTypes[i][0] == 3) ? planesO[eNgons[i][1]] : planesO[eNgons[i][0]]; // Check which edges are connected with bisectors edgePlanes[i] = PlaneUtil.PlaneFromLinePlane(innerLines[i], planeForXAxisRotation); //Take edge vector and rotate it by male plane and in this way get edgePlane //Get vertex ngons int[] CurrentEdgeVertexNgons_I = vertexNGons[Array.IndexOf(allV, ip.I)]; int[] CurrentEdgeVertexNgons_J = vertexNGons[Array.IndexOf(allV, ip.J)]; //Boolean difference between two int faceI = CurrentEdgeVertexNgons_I.Except(CurrentEdgeVertexNgons_J).First(); // int faceJ = CurrentEdgeVertexNgons_J.Except(CurrentEdgeVertexNgons_I).First(); Plane bi = planesO[faceI]; Plane mPlane = new Plane(edgePlanes[i].Origin, bi.XAxis, bi.YAxis); //edgePlanes[i].Rotate(Math.PI*0.5, edgePlanes[i].ZAxis); //edgePlanes[i] = new Plane(edgePlanes[i].Origin, edgePlanes[i].YAxis, edgePlanes[i].XAxis); edgePlanes[i] = PlaneUtil.AlignPlane(edgePlanes[i], mPlane); //edgePlanes[i].Rotate(Math.PI * 0.5, edgePlanes[i].ZAxis); //edgePlanes[i].Rotate(Math.PI * 0.5, edgePlanes[i].ZAxis); } break; } } } //OFFSET PLANES mp = new Plane[allEDict.Count][]; HashSet <int> edges = new HashSet <int>(); int[] e1 = ngonEdges[6]; int[] e2 = ngonEdges[7]; for (int i = 0; i < e1.Length; i++) { edges.Add(allEDict[e1[i]]); } for (int i = 0; i < e2.Length; i++) { edges.Add(allEDict[e2[i]]); } Rhino.RhinoApp.ClearCommandHistoryWindow(); foreach (var edge in edges) { GrasshopperUtil.Debug(edge); } for (int i = 0; i < allEDict.Count; i++) { mp[i] = new Plane[0]; if (jointTypes[i][0] != -1 && jointTypes[i][1] != -1) { //Direction Vector3d vec = Vector3d.Subtract((Vector3d)innerLines[i].From, (Vector3d)innerLines[i].To); vec.Unitize(); vec *= jointWidth; //Distance double dist = innerLines[i].Length - jointWidth; //Draw at least one joint int n = (int)(innerLines[i].Length * 0.5 / jointWidth) - 1; if (innerLines[i].Length > maxLength) { vec.Unitize(); double jointWidth2 = innerLines[i].Length / 10; vec *= jointWidth2; dist = innerLines[i].Length - jointWidth2; //Draw at least one joint n = (int)((innerLines[i].Length * 0.5 / jointWidth2) - 1); } n = (n <= 0) ? 0 : n; //Planes //Define center planes mp[i] = new Plane[n * 2 + 2]; if (dist > 0) { mp[i][n] = new Plane(edgePlanes[i]); mp[i][n].Translate(vec * 0.5); mp[i][n + 1] = new Plane(edgePlanes[i]); mp[i][n + 1].Translate(-vec * 0.5); } //Define rest of the planes for (int j = 1; j < n + 1; j++) { int t = n - j; mp[i][t] = new Plane(edgePlanes[i]); mp[i][t].Translate((j * vec) + (vec * 0.5)); mp[i][j + n + 1] = new Plane(edgePlanes[i]); mp[i][j + n + 1].Translate((j * -vec) - (vec * 0.5)); } if (dist < 0) { mp[i] = new Plane[0]; } //if (edges.Contains(i)) // mp[i] = new Plane[0]; } } //ROTATE PLANES RotatePlaneArray(mp, rotation); //OUTPUT return(mp); }
public static Dictionary <int, Plane> GetCustomAveragePlanes(HashSet <int> allE, Plane[] planesO, int[][] eNgons, int[] allV, Mesh mesh, int[][] ngonEdges, Dictionary <int, int> allEDict) { Dictionary <int, Plane> bisectors = new Dictionary <int, Plane>(); double minAngle = Math.PI / 18 * 3; double maxAngle = Math.PI / 18 * 15; for (int i = 0; i < allE.Count; i++) { int[] ngons = eNgons[i]; double angle = Vector3d.VectorAngle(planesO[ngons[0]].ZAxis, planesO[ngons[1]].ZAxis); if (angle < minAngle || angle > maxAngle) { //Get connected edges to current edges int[] edgesA = ngonEdges[ngons[0]]; int[] ngonPairA = new int[0]; int[] edgesB = ngonEdges[ngons[1]]; int[] ngonPairB = new int[0]; Rhino.IndexPair ip = mesh.TopologyEdges.GetTopologyVertices(allE.ElementAt(i)); for (int j = 0; j < edgesA.Length; j++) { Rhino.IndexPair tempIp = mesh.TopologyEdges.GetTopologyVertices(edgesA[j]); if (ip.I != tempIp.I && ip.J != tempIp.J && ip.J != tempIp.I && ip.I != tempIp.J) { ngonPairA = eNgons[allEDict[edgesA[j]]]; //GrasshopperUtil.Debug(ngonPairA[0]); //GrasshopperUtil.Debug(ngonPairA[1]); break; } } for (int j = 0; j < edgesB.Length; j++) { Rhino.IndexPair tempIp = mesh.TopologyEdges.GetTopologyVertices(edgesB[j]); if (ip.I != tempIp.I && ip.J != tempIp.J && ip.J != tempIp.I && ip.I != tempIp.J) { ngonPairB = eNgons[allEDict[edgesB[j]]]; //GrasshopperUtil.Debug(ngonPairB[0]); //GrasshopperUtil.Debug(ngonPairB[1]); break; } } int faceA = ngonPairB.Except(ngons).First(); int faceB = ngonPairA.Except(ngons).First(); Plane ptemp = planesO[faceA]; ptemp.Flip(); Plane bisector = PlaneUtil.AveragePlane(new Plane[] { ptemp, planesO[faceB] });; bisectors.Add(i, bisector); } } return(bisectors); }
/// <summary> /// This is the method that actually does the work. /// </summary> /// <param name="DA">The DA object is used to retrieve from inputs and store in outputs.</param> protected override void SolveInstance(IGH_DataAccess DA) { Rhino.Geometry.Mesh M = null; if (!DA.GetData(0, ref M)) { return; } List <int> L = new List <int>(); if (!DA.GetDataList(1, L)) { return; } List <double> offset = new List <double>(); if (!DA.GetDataList(2, offset)) { return; } // Check that the mesh is valid, weld all edges, recalculate vertex normals if (!M.IsValid) { return; } /*M.Weld(Math.PI); // Not compatible with Rhino 4! * M.Compact(); * M.UnifyNormals(); * M.Flip(true, true, true);*/ M.Normals.ComputeNormals(); //M.Normals.UnitizeNormals(); int n = M.TopologyVertices.Count; int m = M.TopologyEdges.Count; List <Point3f[]> layers = new List <Point3f[]>(); List <string> bars = new List <string>(); // Add dummy zero offset offset.Insert(0, 0); // for each layer, add two center line "layers" // (note: the first layer of nodes will be "on" the surface of the mesh, otherwise remove "- 0.5 * offset[1]"!) for (int i = 1; i < offset.Count; i++) { Point3f[] l0 = new Point3f[n]; Point3f[] l1 = new Point3f[n]; for (int j = 0; j < n; j++) { int vertex = M.TopologyVertices.MeshVertexIndices(j)[0]; l0[j] = M.TopologyVertices[j] + (float)(2 * offset[i - 1] + 0.5 * offset[i] - 0.5 * offset[1]) * M.Normals[vertex]; l1[j] = M.TopologyVertices[j] + (float)(2 * offset[i - 1] + 1.5 * offset[i] - 0.5 * offset[1]) * M.Normals[vertex]; } layers.Add(l0); layers.Add(l1); } // Remove dummy zero offset offset.RemoveAt(0); // Bars - for each, list by 'line' and by start/end node indices (and calculate gamma angle) List <Line> lines = new List <Line>(); double[] gamma = new double[m]; for (int i = 0; i < m; i++) { Rhino.IndexPair se = M.TopologyEdges.GetTopologyVertices(i); // ------------------------------------------------------------------------------ // GAMMA Vector3d[] normals = new Vector3d[] { M.Normals[M.TopologyVertices.MeshVertexIndices(se.I)[0]], M.Normals[M.TopologyVertices.MeshVertexIndices(se.J)[0]] }; Vector3d avg = normals[0] + normals[1]; Plane vertical = new Plane(M.TopologyVertices[se.I], M.TopologyVertices[se.J], M.TopologyVertices[se.J] + Vector3f.ZAxis); Plane bar = new Plane(M.TopologyVertices[se.I], M.TopologyVertices[se.J], new Point3d(M.TopologyVertices[se.J]) + avg); gamma[i] = (180 * (Vector3d.VectorAngle(vertical.Normal, bar.Normal))) / Math.PI; gamma[i] *= Vector3d.CrossProduct(vertical.Normal, bar.Normal).IsParallelTo(M.TopologyVertices[se.J] - M.TopologyVertices[se.I]); // ------------------------------------------------------------------------------ if (L[i] == 0) { // WARP, add to layers 0, 2, 4, ... for (int j = 0; j < offset.Count; j++) { lines.Add(new Line(layers[2 * j][se.I], layers[2 * j][se.J])); bars.Add(string.Format("{0,6} {1,6}", (2 * j) * n + se.I + 1, (2 * j) * n + se.J + 1)); } } else { // WEFT, add to layers 1, 3, 5, ... for (int j = 0; j < offset.Count; j++) { lines.Add(new Line(layers[2 * j + 1][se.I], layers[2 * j + 1][se.J])); bars.Add(string.Format("{0,6} {1,6}", (2 * j + 1) * n + se.I + 1, (2 * j + 1) * n + se.J + 1)); } } } // Links for (int i = 0; i < M.TopologyVertices.Count; i++) { for (int j = 0; j < layers.Count - 1; j++) { lines.Add(new Line(layers[j][i], layers[j + 1][i])); bars.Add(string.Format("{0,6} {1,6}", (j) * n + i + 1, (j + 1) * n + i + 1)); } } // Nodes - list all by coordinates List <Point3f> nodes = new List <Point3f>(); for (int i = 0; i < layers.Count; i++) { nodes.AddRange(layers[i]); } DA.SetDataList(0, nodes); DA.SetDataList(1, bars); DA.SetDataList(2, gamma); DA.SetDataList(3, lines); }