public PlanarMesher(List <String> tErrorContainer, WingedMesh tWingMesh, Mesh tRhinoMesh, int tNumPanels, int metric, GH_PreviewUtil tPreview) { errorContainer = tErrorContainer; wingMesh = tWingMesh; rhinoMesh = tRhinoMesh; numPanels = tNumPanels; currentPartition = new Partition(wingMesh.faces.Count, this); preview = tPreview; metricRef = metric; }
public PlanarMesher(List<String> tErrorContainer, WingedMesh tWingMesh, Mesh tRhinoMesh, int tNumPanels, int metric, GH_PreviewUtil tPreview) { errorContainer = tErrorContainer; wingMesh = tWingMesh; rhinoMesh = tRhinoMesh; numPanels = tNumPanels; currentPartition = new Partition(wingMesh.faces.Count, this); preview = tPreview; metricRef = metric; }
internal void drawProxies(GH_PreviewUtil preview) { for (int i = 0; i < proxies.Count; i++) { preview.AddMesh(proxies[i].proxyAsMesh); preview.WireColour = UsefulFunctions.returnRandomColour(i); preview.Redraw(); preview.Clear(); } }
protected override void SolveInstance(IGH_DataAccess DA) { //container for errors/messages passed by controller, partition, etc. List<String> errorContainer = new List<String>(); GH_PreviewUtil preview = new GH_PreviewUtil(true); //declare placeholder variables and assign initial empty mesh Mesh baseMesh = new Rhino.Geometry.Mesh(); int errorMetricIdentifer = -1; int numPanels = -1; //Retrieve input data if (!DA.GetData(0, ref baseMesh)) { return; } if (!DA.GetData(1, ref errorMetricIdentifer)) { return; } if (!DA.GetData(2, ref numPanels)) { return; } if (baseMesh.DisjointMeshCount > 1) { this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Problem with mesh input - disjoint mesh"); } else { //compute and unify normal baseMesh.Normals.ComputeNormals(); baseMesh.UnifyNormals(); //create wingedmesh from rhinomesh WingedMesh myMesh = new WingedMesh(errorContainer, baseMesh); PlanarMesher controller = new PlanarMesher(errorContainer, myMesh, baseMesh, numPanels, errorMetricIdentifer, preview); controller.createFirstCluster(); for (int i = 0; i < 40; i++) { controller.iterateCluster(); //controller.currentPartition.drawProxies(preview); } controller.createConnectivityMesh(); //creating voronoi WingedMesh voronoiMesh = new WingedMesh(errorContainer, controller.currentPartition.proxyToMesh.convertWingedMeshToPolylines()); //set all the output data DA.SetDataList(0, voronoiMesh.convertWingedMeshToPolylines()); } foreach (var item in errorContainer) { this.AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, item); } }
/// <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) { Surface S = null; if (!DA.GetData(0, ref S)) { return; } Point3d P = Point3d.Unset; if (!DA.GetData(1, ref P)) { P = S.PointAt(S.Domain(0).Mid, S.Domain(1).Mid); } double R = Rhino.RhinoMath.UnsetValue; if (!DA.GetData(2, ref R)) { return; } double A = Rhino.RhinoMath.UnsetValue; if (!DA.GetData(3, ref A)) { return; } int max = 0; if (!DA.GetData(4, ref max)) { return; } Boolean extend = false; if (!DA.GetData(5, ref extend)) { return; } if (R <= 0) { this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Mesh edge length must be a positive, non-zero number."); return; } // Extend surface beyond boundaries to get a better coverage from the net if (extend) { S = S.Extend(IsoStatus.North, R, true); S = S.Extend(IsoStatus.East, R, true); S = S.Extend(IsoStatus.South, R, true); S = S.Extend(IsoStatus.West, R, true); } // starting point double u0, v0; S.ClosestPoint(P, out u0, out v0); // get two (four) orthogonal directions (in plane of surface at starting point) Plane plane = new Plane(S.PointAt(u0, v0), S.NormalAt(u0, v0)); plane.Rotate(Rhino.RhinoMath.ToRadians(A), S.NormalAt(u0, v0)); Vector3d[] dir = new Vector3d[] { plane.XAxis * R, plane.YAxis * R, plane.XAxis * -R, plane.YAxis * -R }; // for each direction, walk out (and store list of points) double u, v; List <Point3d>[] axis = new List <Point3d> [4]; for (int i = 0; i < 4; i++) { // set u and v to starting point u = u0; v = v0; List <Point3d> pts = new List <Point3d>(); for (int j = 0; j < max + 1; j++) { // get point and normal for uv Point3d pt = S.PointAt(u, v); Vector3d n = S.NormalAt(u, v); n *= R; // add point to list pts.Add(pt); // create forward facing arc and find intersection point with surface (as uv) Arc arc = new Arc(pt + n, pt + dir[i], pt - n); CurveIntersections isct = Intersection.CurveSurface(arc.ToNurbsCurve(), S, 0.01, 0.01); if (isct.Count > 0) { isct[0].SurfacePointParameter(out u, out v); } else { break; } // adjust direction vector (new position - old position) dir[i] = S.PointAt(u, v) - pt; } axis[i] = pts; } // now that we have the axes, start to build up the mesh quads in between GH_PreviewUtil preview = new GH_PreviewUtil(GetValue("Animate", false)); Rhino.Geometry.Mesh mesh = new Rhino.Geometry.Mesh(); // target mesh for (int k = 0; k < 4; k++) { int k0 = (k + 1) % 4; int padding = 10; Rhino.Geometry.Mesh qmesh = new Rhino.Geometry.Mesh(); // local mesh for quadrant Point3d[,] quad = new Point3d[axis[k].Count + padding, axis[k0].Count + padding]; // 2d array of points int[,] qindex = new int[axis[k].Count + padding, axis[k0].Count + padding]; // 2d array of points' indices in local mesh int count = 0; for (int i = 0; i < axis[k0].Count; i++) { // add axis vertex to mesh and store point and index in corresponding 2d arrays quad[0, i] = axis[k0][i]; qmesh.Vertices.Add(axis[k0][i]); qindex[0, i] = count++; } for (int i = 1; i < quad.GetLength(0); i++) { if (i < axis[k].Count) { // add axis vertex quad[i, 0] = axis[k][i]; qmesh.Vertices.Add(axis[k][i]); qindex[i, 0] = count++; } // for each column attempt to locate a new vertex in the grid for (int j = 1; j < quad.GetLength(1); j++) { // if quad[i - 1, j] doesn't exist, try to add it and continue (or else break the current row) if (quad[i - 1, j] == new Point3d()) { if (j < 2) { break; } CurveIntersections isct = this.ArcIntersect(S, quad[i - 1, j - 1], quad[i - 1, j - 2], R); if (isct.Count > 0) { quad[i - 1, j] = isct[0].PointB; qmesh.Vertices.Add(quad[i - 1, j]); qindex[i - 1, j] = count++; } else { break; } } // if quad[i, j - 1] doesn't exist, try to create quad[i, j] by projection and skip mesh face creation if (quad[i, j - 1] == new Point3d()) { if (i < 2) { break; } CurveIntersections isct = this.ArcIntersect(S, quad[i - 1, j], quad[i - 2, j], R); if (isct.Count > 0) { quad[i, j] = isct[0].PointB; qmesh.Vertices.Add(quad[i, j]); qindex[i, j] = count++; continue; } } // construct a sphere at each neighbouring vertex ([i,j-1] and [i-1,j]) and intersect Sphere sph1 = new Sphere(quad[i, j - 1], R); Sphere sph2 = new Sphere(quad[i - 1, j], R); Circle cir; if (Intersection.SphereSphere(sph1, sph2, out cir) == SphereSphereIntersection.Circle) { // intersect circle with surface CurveIntersections cin = Intersection.CurveSurface(NurbsCurve.CreateFromCircle(cir), S, 0.01, 0.01); // attempt to find the new vertex (i.e not [i-1,j-1]) foreach (IntersectionEvent ie in cin) { if ((ie.PointA - quad[i - 1, j - 1]).Length > 0.2 * R) // compare with a tolerance, rather than exact comparison { quad[i, j] = ie.PointA; qmesh.Vertices.Add(quad[i, j]); qindex[i, j] = count++; // create quad-face qmesh.Faces.AddFace(qindex[i, j], qindex[i - 1, j], qindex[i - 1, j - 1], qindex[i, j - 1]); break; } } if (preview.Enabled) { preview.Clear(); preview.AddMesh(mesh); preview.AddMesh(qmesh); preview.Redraw(); } } } } // add local mesh to target mesh.Append(qmesh); } // weld mesh to remove duplicate vertices along axes mesh.Weld(Math.PI); mesh.Compact(); mesh.Normals.ComputeNormals(); DA.SetData(0, mesh); preview.Clear(); }
protected override void SolveInstance(IGH_DataAccess DA) { //container for errors/messages List<String> errorContainer = new List<String>(); GH_PreviewUtil preview = new GH_PreviewUtil(true); //declare placeholder variables and assign initial empty mesh Mesh baseMesh = new Rhino.Geometry.Mesh(); int errorMetricIdentifer = -1; int numPanels = -1; Boolean run = false; //Retrieve input data if (!DA.GetData(0, ref baseMesh)) { return; } if (!DA.GetData(1, ref errorMetricIdentifer)) { return; } if (!DA.GetData(2, ref numPanels)) { return; } if (!DA.GetData(3, ref run)) { return; } if (run) { if (baseMesh.DisjointMeshCount > 1) { errorContainer.Add("Problem with mesh input - disjoint mesh"); } else { //compute and unify normal baseMesh.Normals.ComputeNormals(); baseMesh.UnifyNormals(); //create wingedmesh from rhinomesh WingedMesh myMesh = new WingedMesh(errorContainer, baseMesh); PlanarMesher controller = new PlanarMesher(errorContainer, myMesh, baseMesh, numPanels, errorMetricIdentifer, preview); controller.createFirstCluster(); for (int i = 0; i < 40; i++) { controller.iterateCluster(); controller.currentPartition.drawProxies(preview); } controller.createConnectivityMesh(); //creating voronoi WingedMesh voronoiMesh = new WingedMesh(errorContainer, controller.currentPartition.proxyToMesh.convertWingedMeshToPolylines()); controller.planariseConnectivityMesh(); //convert faces edges to polylines for viewing List<Polyline> boundaryEdges = controller.currentPartition.proxyToMesh.convertWingedMeshToPolylines(); List<Plane> proxyPlanes = new List<Plane>(); foreach (Proxy proxy in controller.currentPartition.proxies) { proxyPlanes.Add(proxy.rhinoPlane); } List<Mesh> proxyMeshes = new List<Mesh>(); foreach (Proxy proxy in controller.currentPartition.proxies) { proxyMeshes.Add(proxy.proxyAsMesh); } List<Vector3d> faceNormals = new List<Vector3d>(); List<Point3d> faceCentres = new List<Point3d>(); for (int i = 0; i < controller.currentPartition.proxyToMesh.faces.Count; i++) { faceNormals.Add(new Vector3d(controller.currentPartition.proxyToMesh.faces[i].faceNormal)); faceCentres.Add(new Point3d(controller.currentPartition.proxyToMesh.faces[i].faceCentre)); } //set all the output data DA.SetDataList(1, proxyPlanes); DA.SetDataList(2, boundaryEdges); DA.SetData(3, controller.currentPartition.proxyToMesh); DA.SetDataList(4, faceNormals); DA.SetDataList(5, faceCentres); DA.SetDataList(6, voronoiMesh.convertWingedMeshToPolylines()); } DA.SetDataList(0, errorContainer); } }
protected override void SolveInstance(IGH_DataAccess DA) { //container for errors/messages passed by controller, partition, etc. List<String> errorContainer = new List<String>(); GH_PreviewUtil preview = new GH_PreviewUtil(true); //declare placeholder variables and assign initial empty mesh List<Curve> baseCurves = new List<Curve>(); //Retrieve input data if (!DA.GetDataList(0, baseCurves)) { this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Couldn't infer list of polyline face boundaries from input"); return; } //if (!DA.GetData(1, ref run)) { return; } List<Polyline> baseMesh = new List<Polyline>(); for (int i = 0; i < baseCurves.Count; i++) { Polyline pl; if (baseCurves[i].TryGetPolyline(out pl)) { baseMesh.Add(pl); } else { this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Couldn't get a polyline from boundary curve #" + i.ToString()); } } try // catch any unexpected errors { // TODO: disjoint mesh check //create wingedmesh from rhinomesh WingedMesh myMesh = new WingedMesh(errorContainer, baseMesh); myMesh.calculateNormals(); PlanarMesher controller = new PlanarMesher(errorContainer, myMesh, null, myMesh.faces.Count, -1, preview); controller.CreateFromInputMesh(); controller.createConnectivityMesh(); controller.planariseConnectivityMesh(); //convert faces edges to polylines for viewing List<Polyline> boundaryEdges = controller.currentPartition.proxyToMesh.convertWingedMeshToPolylines(); List<Plane> proxyPlanes = new List<Plane>(); foreach (Proxy proxy in controller.currentPartition.proxies) { proxyPlanes.Add(proxy.rhinoPlane); } List<Mesh> proxyMeshes = new List<Mesh>(); foreach (Proxy proxy in controller.currentPartition.proxies) { proxyMeshes.Add(proxy.proxyAsMesh); } //set all the output data DA.SetDataList(0, proxyPlanes); DA.SetDataList(1, boundaryEdges); } catch (Exception e) { this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, e.StackTrace); } foreach (var item in errorContainer) { this.AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, item); } }
protected override void SolveInstance(IGH_DataAccess DA) { //container for errors/messages passed by controller, partition, etc. List <String> errorContainer = new List <String>(); GH_PreviewUtil preview = new GH_PreviewUtil(true); //declare placeholder variables and assign initial empty mesh List <Curve> baseCurves = new List <Curve>(); //Retrieve input data if (!DA.GetDataList(0, baseCurves)) { this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Couldn't infer list of polyline face boundaries from input"); return; } //if (!DA.GetData(1, ref run)) { return; } List <Polyline> baseMesh = new List <Polyline>(); for (int i = 0; i < baseCurves.Count; i++) { Polyline pl; if (baseCurves[i].TryGetPolyline(out pl)) { baseMesh.Add(pl); } else { this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Couldn't get a polyline from boundary curve #" + i.ToString()); } } try // catch any unexpected errors { // TODO: disjoint mesh check //create wingedmesh from rhinomesh WingedMesh myMesh = new WingedMesh(errorContainer, baseMesh); myMesh.calculateNormals(); PlanarMesher controller = new PlanarMesher(errorContainer, myMesh, null, myMesh.faces.Count, -1, preview); controller.CreateFromInputMesh(); controller.createConnectivityMesh(); controller.planariseConnectivityMesh(); //convert faces edges to polylines for viewing List <Polyline> boundaryEdges = controller.currentPartition.proxyToMesh.convertWingedMeshToPolylines(); List <Plane> proxyPlanes = new List <Plane>(); foreach (Proxy proxy in controller.currentPartition.proxies) { proxyPlanes.Add(proxy.rhinoPlane); } List <Mesh> proxyMeshes = new List <Mesh>(); foreach (Proxy proxy in controller.currentPartition.proxies) { proxyMeshes.Add(proxy.proxyAsMesh); } //set all the output data DA.SetDataList(0, proxyPlanes); DA.SetDataList(1, boundaryEdges); } catch (Exception e) { this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, e.StackTrace); } foreach (var item in errorContainer) { this.AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, item); } }
protected override void SolveInstance(IGH_DataAccess DA) { //container for errors/messages passed by controller, partition, etc. List <String> errorContainer = new List <String>(); GH_PreviewUtil preview = new GH_PreviewUtil(true); //declare placeholder variables and assign initial empty mesh Mesh baseMesh = new Rhino.Geometry.Mesh(); int errorMetricIdentifer = -1; int numPanels = -1; //Retrieve input data if (!DA.GetData(0, ref baseMesh)) { return; } if (!DA.GetData(1, ref errorMetricIdentifer)) { return; } if (!DA.GetData(2, ref numPanels)) { return; } if (baseMesh.DisjointMeshCount > 1) { this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Problem with mesh input - disjoint mesh"); } else { //compute and unify normal baseMesh.Normals.ComputeNormals(); baseMesh.UnifyNormals(); //create wingedmesh from rhinomesh WingedMesh myMesh = new WingedMesh(errorContainer, baseMesh); PlanarMesher controller = new PlanarMesher(errorContainer, myMesh, baseMesh, numPanels, errorMetricIdentifer, preview); controller.createFirstCluster(); for (int i = 0; i < 40; i++) { controller.iterateCluster(); //controller.currentPartition.drawProxies(preview); } controller.createConnectivityMesh(); //creating voronoi WingedMesh voronoiMesh = new WingedMesh(errorContainer, controller.currentPartition.proxyToMesh.convertWingedMeshToPolylines()); //set all the output data DA.SetDataList(0, voronoiMesh.convertWingedMeshToPolylines()); } foreach (var item in errorContainer) { this.AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, item); } }
protected override void SolveInstance(IGH_DataAccess DA) { //container for errors/messages List <String> errorContainer = new List <String>(); GH_PreviewUtil preview = new GH_PreviewUtil(true); //declare placeholder variables and assign initial empty mesh Mesh baseMesh = new Rhino.Geometry.Mesh(); int errorMetricIdentifer = -1; int numPanels = -1; Boolean run = false; //Retrieve input data if (!DA.GetData(0, ref baseMesh)) { return; } if (!DA.GetData(1, ref errorMetricIdentifer)) { return; } if (!DA.GetData(2, ref numPanels)) { return; } if (!DA.GetData(3, ref run)) { return; } if (run) { if (baseMesh.DisjointMeshCount > 1) { errorContainer.Add("Problem with mesh input - disjoint mesh"); } else { //compute and unify normal baseMesh.Normals.ComputeNormals(); baseMesh.UnifyNormals(); //create wingedmesh from rhinomesh WingedMesh myMesh = new WingedMesh(errorContainer, baseMesh); PlanarMesher controller = new PlanarMesher(errorContainer, myMesh, baseMesh, numPanels, errorMetricIdentifer, preview); controller.createFirstCluster(); for (int i = 0; i < 40; i++) { controller.iterateCluster(); controller.currentPartition.drawProxies(preview); } controller.createConnectivityMesh(); //creating voronoi WingedMesh voronoiMesh = new WingedMesh(errorContainer, controller.currentPartition.proxyToMesh.convertWingedMeshToPolylines()); controller.planariseConnectivityMesh(); //convert faces edges to polylines for viewing List <Polyline> boundaryEdges = controller.currentPartition.proxyToMesh.convertWingedMeshToPolylines(); List <Plane> proxyPlanes = new List <Plane>(); foreach (Proxy proxy in controller.currentPartition.proxies) { proxyPlanes.Add(proxy.rhinoPlane); } List <Mesh> proxyMeshes = new List <Mesh>(); foreach (Proxy proxy in controller.currentPartition.proxies) { proxyMeshes.Add(proxy.proxyAsMesh); } List <Vector3d> faceNormals = new List <Vector3d>(); List <Point3d> faceCentres = new List <Point3d>(); for (int i = 0; i < controller.currentPartition.proxyToMesh.faces.Count; i++) { faceNormals.Add(new Vector3d(controller.currentPartition.proxyToMesh.faces[i].faceNormal)); faceCentres.Add(new Point3d(controller.currentPartition.proxyToMesh.faces[i].faceCentre)); } //set all the output data DA.SetDataList(1, proxyPlanes); DA.SetDataList(2, boundaryEdges); DA.SetData(3, controller.currentPartition.proxyToMesh); DA.SetDataList(4, faceNormals); DA.SetDataList(5, faceCentres); DA.SetDataList(6, voronoiMesh.convertWingedMeshToPolylines()); } DA.SetDataList(0, errorContainer); } }
protected override void SolveInstance(IGH_DataAccess DA) { //Input Surface S = null; if (!DA.GetData(0, ref S)) { return; } Point3d P = Point3d.Unset; if (!DA.GetData(1, ref P)) { P = S.PointAt(S.Domain(0).Mid, S.Domain(1).Mid); } double R = Rhino.RhinoMath.UnsetValue; if (!DA.GetData(2, ref R)) { return; } double A = Rhino.RhinoMath.UnsetValue; if (!DA.GetData(3, ref A)) { return; } int max = 0; if (!DA.GetData(4, ref max)) { return; } Boolean extend = false; if (!DA.GetData(5, ref extend)) { return; } if (R <= 0) { this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Mesh edge length must be a positive, non-zero number."); return; } Surface Sold = S; if (extend) //Extend more and trim edges? { S = S.Extend(IsoStatus.North, R * 2, true); S = S.Extend(IsoStatus.East, R * 2, true); S = S.Extend(IsoStatus.South, R * 2, true); S = S.Extend(IsoStatus.West, R * 2, true); } //----------------------------------------------------------------------------------------------------------// //Solution // starting point double u0, v0; S.ClosestPoint(P, out u0, out v0); //Create plane on surface by point and surface normal, plane x,y axis are directions for the net Plane plane = new Plane(S.PointAt(u0, v0), S.NormalAt(u0, v0)); plane.Rotate(Rhino.RhinoMath.ToRadians(A), S.NormalAt(u0, v0)); Vector3d[] dir = new Vector3d[] { plane.XAxis *R, plane.YAxis *R, plane.XAxis * -R, plane.YAxis * -R }; //Surface Curve[] MyNakedEdges = Sold.ToBrep().DuplicateNakedEdgeCurves(true, false); Mesh[] meshes = new Mesh[] { new Mesh(), new Mesh(), new Mesh(), new Mesh() }; //----------------------------------------------------------------------------------------------------------// //Create axis // for each direction, walk out (and store list of points) double u, v; List <Point3d>[] axis = new List <Point3d> [4]; List <Arc>[] arcs = new List <Arc> [4]; polylines = new List <Polyline>(); for (int i = 0; i < 4; i++) { // set u and v to starting point u = u0; v = v0; List <Point3d> pts = new List <Point3d>(); List <Arc> arcCurrent = new List <Arc>(); for (int j = 0; j < max + 1; j++) { Point3d pt = S.PointAt(u, v); // get point and normal for uv pts.Add(pt); Vector3d srfNormal = S.NormalAt(u, v) * R; Arc arc = new Arc(pt + srfNormal, pt + dir[i], pt - srfNormal); // create forward facing arc and find intersection point with surface (as uv) arcCurrent.Add(arc); CurveIntersections isct = Intersection.CurveSurface(arc.ToNurbsCurve(), S, 0.01, 0.01); if (isct.Count > 0) { isct[0].SurfacePointParameter(out u, out v); } else { break; } // adjust direction vector (new position - old position) dir[i] = S.PointAt(u, v) - pt; } axis[i] = pts; arcs[i] = arcCurrent; } //----------------------------------------------------------------------------------------------------------// //Build up the mesh quads in between GH_PreviewUtil preview = new GH_PreviewUtil(GetValue("Animate", false)); Mesh mesh = new Mesh(); // target mesh for (int k = 0; k < 4; k++) //Loop through each axis { Mesh qmesh = new Mesh(); // local mesh for quadrant int k0 = (k + 1) % 4; //Take neighbour id Point3d[,] quad = new Point3d[axis[k].Count + 10, axis[k0].Count + 10]; // 2d array of points int[,] qindex = new int[axis[k].Count + 10, axis[k0].Count + 10]; // 2d array of points' indices in local mesh int count = 0; for (int i = 0; i < axis[k0].Count; i++) { quad[0, i] = axis[k0][i]; //store 2nd axis points in point array qmesh.Vertices.Add(axis[k0][i]); //also add 2nd axis points to mesh qindex[0, i] = count++; //store indicies } for (int i = 1; i < quad.GetLength(0); i++) { if (i < axis[k].Count) // add axis vertex { quad[i, 0] = axis[k][i]; //store 1st axis points in point array qmesh.Vertices.Add(axis[k][i]); //also add 1st axis points to mesh qindex[i, 0] = count++; //store indicies } // for each column attempt to locate a new vertex in the grid for (int j = 1; j < quad.GetLength(1); j++) { // if quad[i - 1, j] doesn't exist, try to add it and continue (or else break the current row) if (quad[i - 1, j] == new Point3d()) { if (j < 2) { break; } CurveIntersections isct = this.ArcIntersect(S, quad[i - 1, j - 1], quad[i - 1, j - 2], R); if (isct.Count > 0) { quad[i - 1, j] = isct[0].PointB; qmesh.Vertices.Add(quad[i - 1, j]); qindex[i - 1, j] = count++; } else { break; } } // if quad[i, j - 1] doesn't exist, try to create quad[i, j] by projection and skip mesh face creation if (quad[i, j - 1] == new Point3d()) { if (i < 2) { break; } CurveIntersections isct = this.ArcIntersect(S, quad[i - 1, j], quad[i - 2, j], R); if (isct.Count > 0) { quad[i, j] = isct[0].PointB; qmesh.Vertices.Add(quad[i, j]); qindex[i, j] = count++; continue; } } // construct a sphere at each neighbouring vertex ([i,j-1] and [i-1,j]) and intersect Sphere sph1 = new Sphere(quad[i, j - 1], R); Sphere sph2 = new Sphere(quad[i - 1, j], R); Circle cir; if (Intersection.SphereSphere(sph1, sph2, out cir) == SphereSphereIntersection.Circle) { CurveIntersections cin = Intersection.CurveSurface(NurbsCurve.CreateFromCircle(cir), S, 0.01, 0.01);// intersect circle with surface // attempt to find the new vertex (i.e not [i-1,j-1]) foreach (IntersectionEvent ie in cin) { if ((ie.PointA - quad[i - 1, j - 1]).Length > 0.2 * R) // compare with a tolerance, rather than exact comparison { quad[i, j] = ie.PointA; qmesh.Vertices.Add(quad[i, j]); qindex[i, j] = count++; Point3d[] facePt = new Point3d[] { quad[i, j], quad[i - 1, j], quad[i - 1, j - 1], quad[i, j - 1] }; Sold.ClosestPoint(quad[i, j], out double u1, out double v1); Sold.ClosestPoint(quad[i - 1, j], out double u2, out double v2); Sold.ClosestPoint(quad[i - 1, j - 1], out double u3, out double v3); Sold.ClosestPoint(quad[i, j - 1], out double u4, out double v4); double tolerance = 0.01; bool[] flag = new bool[] { Sold.PointAt(u1, v1).DistanceTo(quad[i, j]) < tolerance, Sold.PointAt(u2, v2).DistanceTo(quad[i - 1, j]) < tolerance, Sold.PointAt(u3, v3).DistanceTo(quad[i - 1, j - 1]) < tolerance, Sold.PointAt(u4, v4).DistanceTo(quad[i, j - 1]) < tolerance }; if (flag[0] && flag[1] && flag[2] && flag[3]) { qmesh.Faces.AddFace(qindex[i, j], qindex[i - 1, j], qindex[i - 1, j - 1], qindex[i, j - 1]);// create quad-face } else if (flag[0] || flag[1] || flag[2] || flag[3]) { Polyline temp = new Polyline(); for (int p = 0; p < 4; p++) { switch (Convert.ToInt32(flag[p]) * 10 + Convert.ToInt32(flag[(p + 1) % 4])) { case (11): temp.Add(facePt[p]); break; case (10): temp.Add(facePt[p]); temp.Add(ClosestPointOnNakedEdge(MyNakedEdges, facePt[p], new Line(facePt[p], facePt[(p + 1) % 4]))); break; case (1): temp.Add(ClosestPointOnNakedEdge(MyNakedEdges, facePt[p], new Line(facePt[p], facePt[(p + 1) % 4]))); break; case (0): Sold.ClosestPoint(facePt[p], out double u6, out double v6); temp.Add(Sold.PointAt(u6, v6)); break; } } temp.Close(); polylines.Add(temp); //qmesh.Faces.AddFace(qindex[i, j], qindex[i - 1, j], qindex[i - 1, j - 1], qindex[i, j - 1]);// create quad-face } //qmesh.Faces.AddFace(qindex[i, j], qindex[i - 1, j], qindex[i - 1, j - 1], qindex[i, j - 1]);// create quad-face break; } } if (preview.Enabled) { preview.Clear(); preview.AddMesh(mesh); preview.AddMesh(qmesh); preview.Redraw(); } } } } ; mesh.Append(qmesh);// add local mesh to target } //----------------------------------------------------------------------------------------------------------// //Output mesh.Weld(Math.PI); mesh.Compact(); mesh.Normals.ComputeNormals(); DA.SetData(0, mesh); DA.SetDataTree(1, NGonsCore.GrasshopperUtil.IEOfIEToTree(axis, 0)); DA.SetDataList(2, polylines); preview.Clear(); }
protected override void SolveInstance(IGH_DataAccess DA) { try { //Input Surface S = s; //if (!DA.GetData(0, ref S)) { return; } DA.GetData(0, ref S); Point3d P = Point3d.Unset; if (!DA.GetData(1, ref P)) { P = S.PointAt(S.Domain(0).Mid, S.Domain(1).Mid); } double R = Rhino.RhinoMath.UnsetValue; if (!DA.GetData(2, ref R)) { return; } double A = Rhino.RhinoMath.UnsetValue; if (!DA.GetData(3, ref A)) { return; } int max = 0; if (!DA.GetData(4, ref max)) { return; } Boolean extend = false; if (!DA.GetData(5, ref extend)) { return; } if (R <= 0) { this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Mesh edge length must be a positive, non-zero number."); return; } Mesh cutter = new Mesh(); //DA.GetData(8, ref cutter); Surface Sold = S; Sold.SetDomain(0, new Interval(0, 1)); Sold.SetDomain(1, new Interval(0, 1)); PointCloud cornerPoints = new PointCloud(new Point3d[] { Sold.PointAt(0, 0), Sold.PointAt(0, 1), Sold.PointAt(1, 0), Sold.PointAt(1, 1) }); if (extend) //Extend more and trim edges? { S = S.Extend(IsoStatus.North, R * 2, true); S = S.Extend(IsoStatus.East, R * 2, true); S = S.Extend(IsoStatus.South, R * 2, true); S = S.Extend(IsoStatus.West, R * 2, true); } //int L = 0; //int W = 0; //DA.GetData(6, ref L); //DA.GetData(7, ref W); //----------------------------------------------------------------------------------------------------------// //Solution // starting point double u0, v0; S.ClosestPoint(P, out u0, out v0); //Create plane on surface by point and surface normal, plane x,y axis are directions for the net Plane plane = new Plane(S.PointAt(u0, v0), S.NormalAt(u0, v0)); plane.Rotate(Rhino.RhinoMath.ToRadians(A), S.NormalAt(u0, v0)); Vector3d[] dir = new Vector3d[] { plane.XAxis *R, plane.YAxis *R, plane.XAxis * -R, plane.YAxis * -R }; //Surface Curve[] MyNakedEdges = Sold.ToBrep().DuplicateNakedEdgeCurves(true, false); Curve SurfaceNakedEdge = Curve.JoinCurves(MyNakedEdges)[0]; Mesh[] meshes = new Mesh[] { new Mesh(), new Mesh(), new Mesh(), new Mesh() }; //----------------------------------------------------------------------------------------------------------// //Create axis // for each direction, walk out (and store list of points) double u, v; List <Point3d>[] axis = new List <Point3d> [4]; List <Arc>[] arcs = new List <Arc> [4]; polylines = new List <Polyline>(); for (int i = 0; i < 4; i++) { // set u and v to starting point u = u0; v = v0; List <Point3d> pts = new List <Point3d>(); List <Arc> arcCurrent = new List <Arc>(); for (int j = 0; j < max + 1; j++) { Point3d pt = S.PointAt(u, v); // get point and normal for uv pts.Add(pt); Vector3d srfNormal = S.NormalAt(u, v) * R; Arc arc = new Arc(pt + srfNormal, pt + dir[i], pt - srfNormal); // create forward facing arc and find intersection point with surface (as uv) arcCurrent.Add(arc); CurveIntersections isct = Intersection.CurveSurface(arc.ToNurbsCurve(), S, 0.01, 0.01); if (isct.Count > 0) { isct[0].SurfacePointParameter(out u, out v); } else { break; } // adjust direction vector (new position - old position) dir[i] = S.PointAt(u, v) - pt; } axis[i] = pts; arcs[i] = arcCurrent; } //----------------------------------------------------------------------------------------------------------// //Build up the mesh quads in between Rhino.RhinoApp.ClearCommandHistoryWindow(); GH_PreviewUtil preview = new GH_PreviewUtil(GetValue("Animate", false)); Mesh mesh = new Mesh(); // target mesh Mesh[] fourMeshes = new Mesh[4]; List <int>[] faceID = new List <int>[] { new List <int>(), new List <int>(), new List <int>(), new List <int>() }; //columns lengths List <List <Polyline> >[] strips = new List <List <Polyline> >[] { new List <List <Polyline> >(), new List <List <Polyline> >(), new List <List <Polyline> >(), new List <List <Polyline> >() }; //columns lengths //List<Polyline> cuts = new List<Polyline>(); for (int k = 0; k < 4; k++) //Loop through each axis { Mesh qmesh = new Mesh(); // local mesh for quadrant Point3d[,] quad = new Point3d[axis[k].Count + 10, axis[(k + 1) % 4].Count + 10]; // 2d array of points int[,] qindex = new int[axis[k].Count + 10, axis[(k + 1) % 4].Count + 10]; // 2d array of points' indices in local mesh int count = 0; //Add 2nd axis particles for (int i = 0; i < axis[(k + 1) % 4].Count; i++) { quad[0, i] = axis[(k + 1) % 4][i]; //store 2nd axis points in point array qmesh.Vertices.Add(axis[(k + 1) % 4][i]); //also add 2nd axis points to mesh qindex[0, i] = count++; //store indicies } for (int i = 1; i < quad.GetLength(0); i++) { if (i < axis[k].Count) // add axis vertex { quad[i, 0] = axis[k][i]; //store 1st axis points in point array qmesh.Vertices.Add(axis[k][i]); //also add 1st axis points to mesh qindex[i, 0] = count++; //store indicies } int counter = 0; List <Polyline> currentStrip = new List <Polyline>(); // for each column attempt to locate a new vertex in the grid for (int j = 1; j < quad.GetLength(1); j++) { // if quad[i - 1, j] doesn't exist, try to add it and continue (or else break the current row) if (quad[i - 1, j] == new Point3d()) { if (j < 2) { break; } CurveIntersections isct = this.ArcIntersect(S, quad[i - 1, j - 1], quad[i - 1, j - 2], R); if (isct.Count > 0) { quad[i - 1, j] = isct[0].PointB; qmesh.Vertices.Add(quad[i - 1, j]); qindex[i - 1, j] = count++; } else { break; } } // if quad[i, j - 1] doesn't exist, try to create quad[i, j] by projection and skip mesh face creation if (quad[i, j - 1] == new Point3d()) { if (i < 2) { break; } CurveIntersections isct = this.ArcIntersect(S, quad[i - 1, j], quad[i - 2, j], R); if (isct.Count > 0) { quad[i, j] = isct[0].PointB; qmesh.Vertices.Add(quad[i, j]); qindex[i, j] = count++; continue; } } // construct a sphere at each neighbouring vertex ([i,j-1] and [i-1,j]) and intersect Sphere sph1 = new Sphere(quad[i, j - 1], R); Sphere sph2 = new Sphere(quad[i - 1, j], R); Circle cir; if (Intersection.SphereSphere(sph1, sph2, out cir) == SphereSphereIntersection.Circle) { CurveIntersections cin = Intersection.CurveSurface(NurbsCurve.CreateFromCircle(cir), S, 0.01, 0.01);// intersect circle with surface // attempt to find the new vertex (i.e not [i-1,j-1]) foreach (IntersectionEvent ie in cin) { if ((ie.PointA - quad[i - 1, j - 1]).Length > 0.2 * R) // compare with a tolerance, rather than exact comparison { quad[i, j] = ie.PointA; qmesh.Vertices.Add(quad[i, j]); qindex[i, j] = count++; Point3d[] facePt = new Point3d[] { quad[i, j], quad[i - 1, j], quad[i - 1, j - 1], quad[i, j - 1] }; Sold.ClosestPoint(quad[i, j], out double u1, out double v1); Sold.ClosestPoint(quad[i - 1, j], out double u2, out double v2); Sold.ClosestPoint(quad[i - 1, j - 1], out double u3, out double v3); Sold.ClosestPoint(quad[i, j - 1], out double u4, out double v4); double tolerance = Rhino.RhinoDoc.ActiveDoc.ModelAbsoluteTolerance * 10; bool[] flag = new bool[] { Sold.PointAt(u1, v1).DistanceTo(quad[i, j]) < tolerance, Sold.PointAt(u2, v2).DistanceTo(quad[i - 1, j]) < tolerance, Sold.PointAt(u3, v3).DistanceTo(quad[i - 1, j - 1]) < tolerance, Sold.PointAt(u4, v4).DistanceTo(quad[i, j - 1]) < tolerance }; if (flag[0] && flag[1] && flag[2] && flag[3]) { qmesh.Faces.AddFace(qindex[i, j], qindex[i - 1, j], qindex[i - 1, j - 1], qindex[i, j - 1]);// create quad-face currentStrip.Add(new Polyline() { quad[i, j], quad[i - 1, j], quad[i - 1, j - 1], quad[i, j - 1], quad[i, j] }); counter++; } else if (flag[0] || flag[1] || flag[2] || flag[3]) { Polyline temp = new Polyline() { quad[i, j], quad[i - 1, j], quad[i - 1, j - 1], quad[i, j - 1] }; Polyline trimmedTemp = new Polyline(); //temp = new Polyline() { quad[i, j], quad[i - 1, j], quad[i - 1, j - 1], quad[i, j - 1], quad[i, j] }; double t = R * 0.1; HashSet <int> intersectedSurfaceEdgeId = new HashSet <int>(); for (int l = 0; l < 4; l++) { //If point is ons surface Sold.ClosestPoint(temp[l], out double cpu, out double cpv); if (Sold.PointAt(cpu, cpv).DistanceTo(temp[l]) < Rhino.RhinoDoc.ActiveDoc.ModelAbsoluteTolerance) { trimmedTemp.Add(temp[l]); } //Intersect line segment with closed brep Line faceSegment = new Line(temp[l], temp[MathUtil.Wrap(l + 1, 4)]); Point3d[] meshLinePts = Intersection.MeshLine(cutter, faceSegment, out int[] faceIds); if (meshLinePts.Length > 0) { trimmedTemp.Add(meshLinePts[0]); } } trimmedTemp.Close(); //cuts.Add(trimmedTemp); } break; } } if (preview.Enabled) { preview.Clear(); preview.AddMesh(mesh); preview.AddMesh(qmesh); preview.Redraw(); } } //if sphere intersection } //for j if (currentStrip.Count > 0) { strips[k].Add(currentStrip); } }//for i mesh.Append(qmesh);// add local mesh to target fourMeshes[k] = qmesh; }//for k //----------------------------------------------------------------------------------------------------------// //Output mesh.Weld(Math.PI); mesh.Compact(); mesh.Normals.ComputeNormals(); DA.SetData(0, mesh); DA.SetDataTree(1, NGonsCore.GrasshopperUtil.IE2(axis, 0)); this.PreparePreview(mesh, DA.Iteration, null, true, null, mesh.GetEdges()); //DA.SetDataList(2, cuts); //DA.SetDataTree(3, NGonsCore.GrasshopperUtil.IE4(patches.ToList(), 0)); //DA.SetDataList(4, fourMeshes); //DA.SetDataTree(5, GrasshopperUtil.IE3(strips, 0)); preview.Clear(); }catch (Exception e) { GrasshopperUtil.Debug(e); } }