internal void MoveAllPointsDepthDependant(CuttingInfo info, DMesh3 newMesh, Dictionary <int, BacksideAlgorithm.PeprStatusVert> stati) { var tree = new DMeshAABBTree3(info.oldMesh, true); tree.TriangleFilterF = i => tree.Mesh.GetTriangleGroup(i) != info.data.ColorNum; foreach (var status in stati) { var shellPoint = newMesh.GetVertex(status.Value.idNewMeshOuter.Value); var normal = info.oldMesh.CalcVertexNormal(status.Value.idOldMeshOuter); var position = shellPoint + info.data.minDepth * normal; Ray3d ray = new Ray3d(shellPoint - normal * info.data.minDepth, -normal); //tiny shift to make sure it's not hitting itself int hit_tid = tree.FindNearestHitTriangle(ray); Debug.Log("Hit " + hit_tid); if (hit_tid != DMesh3.InvalidID) { IntrRay3Triangle3 intr = MeshQueries.TriangleIntersection(info.oldMesh, hit_tid, ray); double hit_dist = shellPoint.Distance(ray.PointAt(intr.RayParameter)); position = shellPoint - normal * hit_dist * (info.data.depth / 100); Debug.Log($"Hit Dist: {hit_dist}"); } else { StaticFunctions.ErrorMessage("Depth Dependant Calculation has encountered an error"); } info.mesh.SetVertex(status.Value.idOldMeshInner.Value, position); newMesh.SetVertex(status.Value.idNewMeshInner.Value, position); } }
public static Matrix2d GetMatrixFromRayShoot(Grid grid, Mesh union, bool top = false) { Matrix2d grid2d = new Matrix2d(grid.NumX, grid.NumY); double zDim = -MAX_LIMIT; Vector3d axis = Vector3d.ZAxis; if (top) { zDim = MAX_LIMIT; axis = -Vector3d.ZAxis; } for (int i = 0; i < grid.NumX; i++) { for (int j = 0; j < grid.NumY; j++) { Point3d point = new Point3d((i * grid.DimX) + grid.MinX, (j * grid.DimY) + grid.MinY, zDim); Ray3d ray = new Ray3d(point, axis); var intersection = Rhino.Geometry.Intersect.Intersection.MeshRay(union, ray); if (intersection != -1.0) { int value = (int)Math.Round((float)ray.PointAt(intersection).Z, MidpointRounding.AwayFromZero); if (value < 0) { value = 0; } grid2d[i, j] = value; } } } return(grid2d); }
/// <summary> /// エージェントの視野を障害物か視野半径でカットするメソッド /// </summary> /// <returns></returns> /// /// 20190622 Matsu 作成 /// 20190629 Matsu 交点がないときの処理を追加 public void CutViewRay() { var intersectVecLs = new List <Vector3d>(); var centerPt = agent.AgentBasePlane.Origin; List <Point3d> intersectPt = new List <Point3d>(); //エージェントのビューから取得 var vecLs = ShootRayView(); for (var i = 0; i < vecLs.Count; i++) { var ray = new Ray3d(centerPt, vecLs[i]); try { intersectPt = Rhino.Geometry.Intersect.Intersection.RayShoot(ray, agent.Obstacles, 1).ToList(); } catch (ArgumentNullException) { Point3d pt = ray.PointAt(agent.ViewRaidius); intersectPt.Add(pt); } IsInnerRadius(centerPt, intersectPt[0], out Vector3d vec); intersectVecLs.Add(vec); } //エージェントクラス内に格納 agent.AgentViewRay = intersectVecLs; }
///Projection engines public static GH_Point ProjectPointToTopo(Mesh topoMesh, Point3d pt) { GH_Point ghPoint = new GH_Point(); Ray3d ray = new Ray3d(pt, moveDir); double t = Rhino.Geometry.Intersect.Intersection.MeshRay(topoMesh, ray); if (t >= 0.0) { GH_Convert.ToGHPoint(ray.PointAt(t), GH_Conversion.Primary, ref ghPoint); } else { Ray3d rayOpp = new Ray3d(pt, -moveDir); double tOpp = Rhino.Geometry.Intersect.Intersection.MeshRay(topoMesh, rayOpp); if (tOpp >= 0.0) { GH_Convert.ToGHPoint(rayOpp.PointAt(tOpp), GH_Conversion.Primary, ref ghPoint); } else { return(null); } } return(ghPoint); }
public static List <Point3d> GetMatrixFromRayShoot(Grid grid, Mesh union, ref Matrix2d matrix) { List <Point3d> points = new List <Point3d>(); int zDim = Building.MAX_LIMIT; Vector3d axis = -Vector3d.ZAxis; for (int i = 0; i < grid.NumX; i++) { for (int j = 0; j < grid.NumY; j++) { Point3d point = new Point3d((i * grid.DimX) + grid.MinX, (j * grid.DimY) + grid.MinY, zDim); Ray3d ray = new Ray3d(point, axis); var intersection = Rhino.Geometry.Intersect.Intersection.MeshRay(union, ray); if (intersection != -1.0) { double value = ray.PointAt(intersection).Z; if (value < 0) { value = 0; } Grid.FilterListBasedOnNumber(grid.Height.ToList(), value).ForEach(v => { points.Add(new Point3d(point.X, point.Y, v)); }); matrix[i, j] = (int)Math.Round((float)value, MidpointRounding.AwayFromZero); } } } return(points); }
public static GH_Mesh ProjectMeshToTopoFast(Mesh topoMesh, Mesh featureMesh) { GH_Mesh ghMesh = new GH_Mesh(); Mesh mesh = featureMesh.DuplicateMesh(); ///Move patch verts to topo for (int i = 0; i < mesh.Vertices.Count; i++) { Ray3d ray = new Ray3d((Point3d)mesh.Vertices[i], moveDir); double t = Rhino.Geometry.Intersect.Intersection.MeshRay(topoMesh, ray); if (t >= 0.0) { mesh.Vertices.SetVertex(i, (Point3f)ray.PointAt(t)); } else { Ray3d rayOpp = new Ray3d((Point3d)mesh.Vertices[i], -moveDir); double tOpp = Rhino.Geometry.Intersect.Intersection.MeshRay(topoMesh, rayOpp); if (tOpp >= 0.0) { mesh.Vertices.SetVertex(i, (Point3f)rayOpp.PointAt(tOpp)); } else { //mesh.Vertices.SetVertex(i, new Point3f(0, 0, 0)); //return null; } } } GH_Convert.ToGHMesh(mesh, GH_Conversion.Primary, ref ghMesh); return(ghMesh); }
public TerrainMap(WorldMap _world, Mesh m) { World = _world; int sz_X = (int)(World.boundary.Width / World.resolution); int sz_Y = (int)(World.boundary.Height / World.resolution); double resX = World.boundary.Width / sz_X; double resY = World.boundary.Height / sz_Y; Points = new Point3d[sz_X, sz_Y]; Map = new Terrain[sz_X, sz_Y]; xLen = sz_X; yLen = sz_Y; //divide the rectangle into little rectangles, and assign location to be the midpoint of those rectangles. //set the locX, locY, value appropriately for MapArray for (int y = 0; y < sz_Y; y++) { for (int x = 0; x < sz_X; x++) { Points[x, y] = World.boundary.Plane.Origin + (0.5 + x) * resX * World.boundary.Plane.XAxis + (0.5 + y) * resY * World.boundary.Plane.YAxis; Map[x, y] = new Terrain(this); Map[x, y].locX = x; Map[x, y].locY = y; Map[x, y].val = 0; Map[x, y].neighbours = new List <Terrain>(); } } //store neighbours for (int x = 0; x < sz_X; x++) { for (int y = 0; y < sz_Y; y++) { Map[x, y].GenerateNeighbours(); } } //from here do stuff that is specific to the implementation. In this case //terrain will change the values in the mapArray accordingly to reflect the landscape //of the mesh passed to it in the constructor. double safeHeight = m.GetBoundingBox(true).Max.Z + 10.0; for (int x = 0; x < xLen; x++) { for (int y = 0; y < yLen; y++) { Point3d point = Points[x, y]; point.Z = safeHeight; Ray3d ray = new Ray3d(point, -Vector3d.ZAxis); double t = Rhino.Geometry.Intersect.Intersection.MeshRay(m, ray); Point3d projected = ray.PointAt(t); Map[x, y].val = projected.Z; } } }
private void FindMeshNodes() { NurbsCurve boundary = CaveTools.GetPlanarPanelBoundary(this); for (int c = 0; c < nodeGrid.Count; c++) { List <Curve> row = new List <Curve>(); for (int d = 0; d < nodeGrid[c].Count; d++) { Ray3d ray = new Ray3d(nodeGrid[c][d], localPlane.ZAxis); double t = Rhino.Geometry.Intersect.Intersection.MeshRay(CavePanels, ray); if (t >= 0) { meshnodes[c][d].point = ray.PointAt(t); meshnodes[c][d].pointset = true; //is it too close to edge double p = 0; boundary.ClosestPoint(nodeGrid[c][d], out p); Point3d boundaryPt = boundary.PointAt(p); double dist = nodeGrid[c][d].DistanceTo(boundaryPt); if (dist < parameters.cellGap / 2 - 5) { ghostNodesFound = true; meshnodes[c][d].isGhost = true; } } else { Polyline[] edges = CavePanels.GetNakedEdges(); double minDist = double.MaxValue; Point3d closest = new Point3d(); Line drop = new Line(nodeGrid[c][d], localPlane.Normal, 1000); Point3d meshPt = new Point3d(); foreach (Polyline pl in edges) { foreach (Point3d pt in pl) { Point3d temp = drop.ClosestPoint(pt, false); if (temp.DistanceTo(pt) < minDist) { minDist = temp.DistanceTo(pt); closest = temp; meshPt = pt; } } } meshnodes[c][d].point = closest; meshnodes[c][d].pointset = true; meshnodes[c][d].isGhost = true; ghostNodesFound = true; //RhinoDoc.ActiveDoc.Objects.AddPoint(meshnodes[c][d].point); } } } }
public static Mesh MoveBuildingsUp(Mesh mesh, Mesh terrain) { Transform xmoveTerrain; Transform xmoveCentroid; const int UnitBox = 1; const double noIntersection = 0.0; Mesh newMesh = mesh.DuplicateMesh(); try { // first traslation Point3d center = AreaMassProperties.Compute(newMesh).Centroid; Ray3d r = new Ray3d(center, Vector3d.ZAxis); var intersec = Rhino.Geometry.Intersect.Intersection.MeshRay(terrain, r); Point3d pt = r.PointAt(intersec); if (intersec != noIntersection) { Vector3d vecCentroid = new Vector3d(0, 0, pt.Z - center.Z); xmoveCentroid = Transform.Translation(vecCentroid); newMesh.Transform(xmoveCentroid); } // move to terrain BoundingBox BBox = newMesh.GetBoundingBox(true); Mesh meshBox = Mesh.CreateFromBox(BBox, UnitBox, UnitBox, UnitBox); Line[] lines = Rhino.Geometry.Intersect.Intersection.MeshMeshFast(terrain, newMesh); Point3d minBBox = BBox.Min; // dimension double start = minBBox.Z; double end = lines.Min(l => l.From.Z); Vector3d vecTerrain = new Vector3d(0, 0, end - start); xmoveTerrain = Transform.Translation(vecTerrain); } catch { xmoveTerrain = Transform.Translation(Vector3d.Zero); } newMesh.Transform(xmoveTerrain); return(newMesh); }
public static double?DistanceToTree(this DMeshAABBTree3 tree, Ray3d ray) { var hit_tid = tree.FindNearestHitTriangle(ray); if (hit_tid == DMesh3.InvalidID) { return(null); } var intr = MeshQueries.TriangleIntersection(tree.Mesh, hit_tid, ray); return(ray.Origin.Distance(ray.PointAt(intr.RayParameter))); }
private void FindMeshCurve() { for (int i = 0; i <= 50; i++) { Point3d p = gridLine.PointAt(1.0 / 50 * i); Ray3d ray = new Ray3d(p, toPanel); double t = Rhino.Geometry.Intersect.Intersection.MeshRay(panel, ray); if (t >= 0) { panelCurvepts.Add(ray.PointAt(t)); } } panelCurve = NurbsCurve.Create(false, 1, panelCurvepts); }
private void FindIntersectsToKeep() { //compare to point grid to remove if too close for (int i = 0; i < interpts.Count; i++) { Point3d closest = CaveTools.ClosestPoint(interpts[i], planarPointGrid.SelectMany(x => x).ToList()); if (closest.DistanceTo(interpts[i]) > parameters.cellGap / 4) { Ray3d ray = new Ray3d(interpts[i], panelFrame.localPlane.ZAxis); double t = Rhino.Geometry.Intersect.Intersection.MeshRay(panelFrame.CavePanels, ray); if (t >= 0) { meshpts.Add(ray.PointAt(t)); } } } }
public static GH_Surface ProjectSurfaceToTopoFast(Mesh topoMesh, Surface featureSurface) { GH_Surface ghSurface = new GH_Surface(); NurbsSurface surface = featureSurface.ToNurbsSurface(); ///Move patch verts to topo for (int u = 0; u < surface.Points.CountU; u++) { for (int v = 0; v < surface.Points.CountV; v++) { Point3d controlPt; surface.Points.GetPoint(u, v, out controlPt); Ray3d ray = new Ray3d(controlPt, moveDir); double t = Rhino.Geometry.Intersect.Intersection.MeshRay(topoMesh, ray); if (t >= 0.0) { surface.Points.SetPoint(u, v, ray.PointAt(t)); } else { Ray3d rayOpp = new Ray3d(controlPt, -moveDir); double tOpp = Rhino.Geometry.Intersect.Intersection.MeshRay(topoMesh, rayOpp); if (tOpp >= 0.0) { surface.Points.SetPoint(u, v, rayOpp.PointAt(t)); } else { //return null; } } } } if (surface.IsValid) { GH_Convert.ToGHSurface(surface, GH_Conversion.Primary, ref ghSurface); return(ghSurface); } else { return(null); } }
public static GH_Curve ProjectPolylineToTopo(Mesh topoMesh, Polyline pLine) { GH_Curve ghCurve = new GH_Curve(); List <Point3d> projectedPts = new List <Point3d>(); for (int j = 0; j < pLine.Count; j++) { Ray3d ray = new Ray3d(pLine[j], moveDir); double t = Rhino.Geometry.Intersect.Intersection.MeshRay(topoMesh, ray); if (t >= 0.0) { projectedPts.Add(ray.PointAt(t)); } else { Ray3d rayOpp = new Ray3d(pLine[j], -moveDir); double tOpp = Rhino.Geometry.Intersect.Intersection.MeshRay(topoMesh, rayOpp); if (tOpp >= 0.0) { projectedPts.Add(rayOpp.PointAt(tOpp)); } else { //return null; } } } Polyline pLineOut = new Polyline(projectedPts); if (pLineOut.IsValid) { GH_Convert.ToGHCurve(pLineOut.ToNurbsCurve(), GH_Conversion.Primary, ref ghCurve); return(ghCurve); } else { return(null); } }
/// <summary> /// Find intersection of *WORLD* ray with Mesh /// </summary> override public bool FindRayIntersection(Ray3f rayW, out SORayHit hit) { hit = null; if (enable_spatial == false) { return(false); } validate_spatial(); // convert ray to local FScene scene = this.GetScene(); Ray3f rayS = scene.ToSceneRay(rayW); Ray3d local_ray = SceneTransforms.SceneToObject(this, rayS); int hit_tid = spatial.FindNearestHitTriangle(local_ray); if (hit_tid != DMesh3.InvalidID) { IntrRay3Triangle3 intr = MeshQueries.TriangleIntersection(mesh, hit_tid, local_ray); Vector3f hitPos = (Vector3f)local_ray.PointAt(intr.RayParameter); hitPos = SceneTransforms.ObjectToSceneP(this, hitPos); hitPos = scene.ToWorldP(hitPos); Vector3f hitNormal = (Vector3f)mesh.GetTriNormal(hit_tid); hitNormal = SceneTransforms.ObjectToSceneN(this, hitNormal); hitNormal = scene.ToWorldN(hitNormal); hit = new SORayHit(); hit.hitPos = hitPos; hit.hitNormal = hitNormal; hit.hitIndex = hit_tid; hit.fHitDist = hit.hitPos.Distance(rayW.Origin); // simpler than transforming! hit.hitGO = RootGameObject; hit.hitSO = this; return(true); } return(false); }
/// <summary> /// Find intersection of *WORLD* ray with Mesh /// </summary> override public bool FindRayIntersection(Ray3f rayW, out SORayHit hit) { hit = null; if (enable_spatial == false) { return(false); } if (spatial == null) { spatial = new DMeshAABBTree3(mesh); spatial.Build(); } // convert ray to local Frame3f f = new Frame3f(rayW.Origin, rayW.Direction); f = SceneTransforms.TransformTo(f, this, CoordSpace.WorldCoords, CoordSpace.ObjectCoords); Ray3d local_ray = new Ray3d(f.Origin, f.Z); int hit_tid = spatial.FindNearestHitTriangle(local_ray); if (hit_tid != DMesh3.InvalidID) { IntrRay3Triangle3 intr = MeshQueries.TriangleIntersection(mesh, hit_tid, local_ray); Frame3f hitF = new Frame3f(local_ray.PointAt(intr.RayParameter), mesh.GetTriNormal(hit_tid)); hitF = SceneTransforms.TransformTo(hitF, this, CoordSpace.ObjectCoords, CoordSpace.WorldCoords); hit = new SORayHit(); hit.hitPos = hitF.Origin; hit.hitNormal = hitF.Z; hit.hitIndex = hit_tid; hit.fHitDist = hit.hitPos.Distance(rayW.Origin); // simpler than transforming! hit.hitGO = RootGameObject; hit.hitSO = this; return(true); } return(false); }
public static Vector3d GetMinProjectedPointToMesh(List <Point3d> points, Mesh topoMesh) { List <Point3d> projectedPts = new List <Point3d>(); foreach (Point3d pt in points) { Ray3d ray = new Ray3d(pt, moveDir); double t = Rhino.Geometry.Intersect.Intersection.MeshRay(topoMesh, ray); if (t >= 0.0) { projectedPts.Add(ray.PointAt(t)); } else { Ray3d rayOpp = new Ray3d(pt, -moveDir); double tOpp = Rhino.Geometry.Intersect.Intersection.MeshRay(topoMesh, rayOpp); if (tOpp >= 0.0) { projectedPts.Add(rayOpp.PointAt(tOpp)); } else { return(new Vector3d(0, 0, Double.MaxValue)); } } } Vector3d min_v = new Vector3d(0, 0, Double.MaxValue); for (int i = 0; i < points.Count; i++) { Vector3d v = projectedPts[i] - points[i]; if (v.Length < min_v.Length) { min_v = v; } } return(min_v); }
// [RMS] this is not working right now... override public bool FindRayIntersection(Ray3f ray, out SORayHit hit) { hit = null; if (enable_spatial == false) { return(false); } if (spatial == null) { spatial = new DMeshAABBTree3(mesh); spatial.Build(); } Transform xform = ((GameObject)RootGameObject).transform; // convert ray to local Ray3d local_ray = new Ray3d(); local_ray.Origin = xform.InverseTransformPoint(ray.Origin); local_ray.Direction = xform.InverseTransformDirection(ray.Direction); local_ray.Direction.Normalize(); int hit_tid = spatial.FindNearestHitTriangle(local_ray); if (hit_tid != DMesh3.InvalidID) { IntrRay3Triangle3 intr = MeshQueries.TriangleIntersection(mesh, hit_tid, local_ray); hit = new SORayHit(); hit.fHitDist = (float)intr.RayParameter; hit.hitPos = xform.TransformPoint((Vector3f)local_ray.PointAt(intr.RayParameter)); hit.hitNormal = xform.TransformDirection((Vector3f)mesh.GetTriNormal(hit_tid)); hit.hitGO = RootGameObject; hit.hitSO = this; return(true); } return(false); }
/// <summary> /// Rayを飛ばして一歩進めるかどうか判定する /// </summary> /// <param name="ray"></param> /// <returns></returns> /// /// 20190622 Matsu 作成 public virtual bool IsGoing(Ray3d ray) { List <Point3d> intersectPt = new List <Point3d>(); try { intersectPt = Rhino.Geometry.Intersect.Intersection.RayShoot(ray, agent.Obstacles, 1).ToList(); } catch (ArgumentNullException) { Point3d pt = ray.PointAt(agent.ViewRaidius); intersectPt.Add(pt); } // 交点との距離が1歩以上ならTrue、以下ならFalseを返す if (agent.AgentBasePlane.Origin.DistanceTo(intersectPt[0]) > agent.StepCount) { return(true); } else { return(false); } }
public bool RayIntersect(Ray3d ray, out Vector3D vHit, out Vector3D vHitNormal) { vHit = Vector3D.Zero; vHitNormal = Vector3D.AxisX; int tHitID = Spatial.FindNearestHitTriangle(ray); if (tHitID == NGonsCore.geometry3Sharp.mesh.DMesh3.InvalidID) { return(false); } IntrRay3Triangle3 t = MeshQueries.TriangleIntersection(Mesh, tHitID, ray); vHit = ray.PointAt(t.RayParameter); if (UseFaceNormal == false && Mesh.HasVertexNormals) { vHitNormal = Mesh.GetTriBaryNormal(tHitID, t.TriangleBaryCoords.x, t.TriangleBaryCoords.y, t.TriangleBaryCoords.z); } else { vHitNormal = Mesh.GetTriNormal(tHitID); } return(true); }
void update_current_hole_type() { if (HoleType == HoleTypes.CutHole) { if (CutOp != null) { CutOp.StartPoint = LastUpdateRay.Origin; CutOp.EndPoint = LastUpdateRay.PointAt(LastThroughDepth); } } if (HoleType == HoleTypes.CavityObject || AlwaysShowPreview) { Frame3f holeFrame = new Frame3f(LastUpdateRay.Origin, LastUpdateRay.Direction); holeFrame.Translate((float)(-CurEndOffset) * holeFrame.Z); Frame3f holeFrameS = SceneTransforms.ObjectToScene(InputMeshSO, holeFrame); CavityPreviewSO.SetLocalFrame(holeFrameS, CoordSpace.SceneCoords); CavityPreviewSO.SetLocalScale(new Vector3f(hole_size, hole_size, (float)CurHoleDepth)); } active_hole_type = HoleType; }
internal Vector3d MovePointDepthDependant(CuttingInfo info, Vector3d shellPoint, Vector3d normal) { normal = normal.Normalized; var position = shellPoint + info.data.minDepth * normal;; var tree = new DMeshAABBTree3(info.oldMesh, true); Ray3d ray = new Ray3d(shellPoint, -normal); int hit_tid = tree.FindNearestHitTriangle(ray); Debug.Log("Hit " + hit_tid); if (hit_tid != DMesh3.InvalidID) { IntrRay3Triangle3 intr = MeshQueries.TriangleIntersection(info.oldMesh, hit_tid, ray); double hit_dist = shellPoint.Distance(ray.PointAt(intr.RayParameter)); position = shellPoint - normal * hit_dist * (info.data.depth / 100); Debug.Log($"Hit Dist: {hit_dist}"); } else { StaticFunctions.ErrorMessage("Depth Dependant Calculation failed"); } return(position); }
protected override void SolveInstance(IGH_DataAccess DA) { if (DA.Iteration > 1) { AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "超出数据已被忽视"); return; } Mesh tm = new Mesh(); if (!DA.GetData(0, ref tm) && !tm.IsValid) { return; } List <Mesh> o = new List <Mesh>(3); DA.GetDataList(1, o); List <Point3d> pl = new List <Point3d>(); if (!DA.GetDataList(2, pl)) { return; } int a = 0; if (!DA.GetData(3, ref a)) { return; } #region 制作网格上用于测量的点阵 BoundingBox mb = new BoundingBox(); foreach (Point3f p3f in tm.Vertices) { mb.Union(new Point3d(p3f)); } double px = mb.Min.X; double py = mb.Min.Y; int rx = (int)Math.Ceiling((mb.Max.X - px) / a); int ry = (int)Math.Ceiling((mb.Max.Y - py) / a); List <Point3d> grid = new List <Point3d>(rx * ry); for (int ix = 0; ix < rx; ix++) { for (int iy = 0; iy < ry; iy++) { Ray3d ray = new Ray3d(new Point3d(px, py, mb.Min.Z), Vector3d.ZAxis); double pmd = Intersection.MeshRay(tm, ray); if (RhinoMath.IsValidDouble(pmd) && pmd > 0.0) { grid.Add(ray.PointAt(pmd)); } py += a; } px += a; py = mb.Min.Y; } //获取网格上点阵制作栅格点阵z射线,与网格相交,交点加入grid #endregion List <Point3d> pt = new List <Point3d>(pl.Count); #region 将观测点投影到地形网格上,并增加眼高 foreach (Point3d p0 in pl) { Point3d p = p0; Ray3d rayp = new Ray3d(new Point3d(p.X, p.Y, mb.Min.Z), Vector3d.ZAxis); double pmdp = Intersection.MeshRay(tm, rayp); if (RhinoMath.IsValidDouble(pmdp) && pmdp > 0.0) { p = rayp.PointAt(pmdp); } else { AddRuntimeMessage(GH_RuntimeMessageLevel.Error, $"观测点{p}无法被Z向投影至地形网格上"); return; } p.Z += 1.5; //增加眼高 pt.Add(p); } //采样点 #endregion foreach (Mesh m in o) //将障碍物附加入网格 { tm.Append(m); } bool[] grib = new bool[grid.Count]; //采样点布尔数组 foreach (Point3d p in pt) { if (Environment.ProcessorCount > 2) { Parallel.For(0, grid.Count, j => //多线程处理每个采样点 { if (!grib[j]) //grib为否(尚未可见)时 判定当前是否为可见点,与网格上的点阵交点仅为1的即可见点 { grib[j] = Intersection.MeshLine(tm, new Line(p, grid[j]), out _).Length == 1; } }); } else { for (int j = 0; j < grid.Count; j++) { if (!grib[j]) //grib为否(尚未可见)时 判定当前是否为可见点,与网格上的点阵交点仅为1的即可见点 { grib[j] = Intersection.MeshLine(tm, new Line(p, grid[j]), out _).Length == 1; } } } } for (int i = grid.Count - 1; i >= 0; i--) //剔除不可见点 { if (!grib[i]) { grid.RemoveAt(i); } } DA.SetDataList(0, pt); DA.SetDataList(1, grid); }
protected override Rhino.Commands.Result RunCommand(RhinoDoc doc, Rhino.Commands.RunMode mode) { Mesh meshObj; Point3d pointObj = new Point3d(0.0,0.0,0.0); RhinoApp.WriteLine("dikka dikka dikka..."); Rhino.Input.Custom.GetPoint gp = new Rhino.Input.Custom.GetPoint(); gp.SetCommandPrompt("Start of ray"); gp.Get(); if (gp.CommandResult() != Rhino.Commands.Result.Success) return gp.CommandResult(); pointObj = gp.Point(); doc.Objects.AddPoint(pointObj); Rhino.Input.Custom.GetObject go = new Rhino.Input.Custom.GetObject(); go.SetCommandPrompt("Select the mesh to print"); go.Get(); Result rc = go.CommandResult(); if (rc != Rhino.Commands.Result.Success) { RhinoApp.WriteLine("sdfafadsfda"); return rc; } RhinoApp.WriteLine("2 2 dikka dikka dikka..."); meshObj = new Mesh(); if (go.ObjectCount == 1) { ObjRef tmpRef = new ObjRef(go.Object(0).ObjectId); meshObj = tmpRef.Mesh(); if (meshObj == null) { return rc; } } Ray3d rayObj = new Ray3d(pointObj, new Vector3d(1.0, 1.0, 1.0)); doc.Objects.AddPoint(rayObj.PointAt(1.0)); doc.Objects.AddPoint(rayObj.PointAt(2.0)); doc.Objects.AddPoint(rayObj.PointAt(3.0)); double p = Intersection.MeshRay(meshObj, rayObj); string a = string.Format("mesh ray gives {0:0.00}",p); doc.Objects.AddPoint(rayObj.PointAt(p)); RhinoApp.WriteLine(a); return Rhino.Commands.Result.Success; }
protected override void SolveInstance(IGH_DataAccess DA) { ITargetLength TargetLength = null; bool reset = false; int Flip = 0; List<Curve> FC = new List<Curve>(); List<Point3d> FV = new List<Point3d>(); double FixT = 0.01; double PullStrength = 0.8; double SmoothStrength = 0.8; double LengthTol = 0.15; bool Minim = false; int Iters = 1; GH_ObjectWrapper Surf = new GH_ObjectWrapper(); DA.GetData<GH_ObjectWrapper>(0, ref Surf); GH_ObjectWrapper Obj = null; DA.GetData<GH_ObjectWrapper>(1, ref Obj); TargetLength = Obj.Value as ITargetLength; DA.GetDataList<Curve>(2, FC); DA.GetDataList<Point3d>(3, FV); DA.GetData<int>(4, ref Flip); DA.GetData<double>(5, ref PullStrength); DA.GetData<int>(6, ref Iters); DA.GetData<bool>(7, ref reset); if (PullStrength == 0) { Minim = true; } if (Surf.Value is GH_Mesh) { DA.GetData<Mesh>(0, ref M); M.Faces.ConvertQuadsToTriangles(); } else { double L = 1.0; MeshingParameters MeshParams = new MeshingParameters(); MeshParams.MaximumEdgeLength = 3 * L; MeshParams.MinimumEdgeLength = L; MeshParams.JaggedSeams = false; MeshParams.SimplePlanes = false; Brep SB = null; DA.GetData<Brep>(0, ref SB); Mesh[] BrepMeshes = Mesh.CreateFromBrep(SB, MeshParams); M = new Mesh(); foreach (var mesh in BrepMeshes) M.Append(mesh); } if (reset || initialized == false) { #region reset M.Faces.ConvertQuadsToTriangles(); P = M.ToPlanktonMesh(); initialized = true; AnchorV.Clear(); FeatureV.Clear(); FeatureE.Clear(); //Mark any vertices or edges lying on features for (int i = 0; i < P.Vertices.Count; i++) { Point3d Pt = P.Vertices[i].ToPoint3d(); AnchorV.Add(-1); for (int j = 0; j < FV.Count; j++) { if (Pt.DistanceTo(FV[j]) < FixT) { AnchorV[AnchorV.Count - 1] = j; } } FeatureV.Add(-1); for (int j = 0; j < FC.Count; j++) { double param = new double(); FC[j].ClosestPoint(Pt, out param); if (Pt.DistanceTo(FC[j].PointAt(param)) < FixT) { FeatureV[FeatureV.Count - 1] = j; } } } int EdgeCount = P.Halfedges.Count / 2; for (int i = 0; i < EdgeCount; i++) { FeatureE.Add(-1); int vStart = P.Halfedges[2 * i].StartVertex; int vEnd = P.Halfedges[2 * i + 1].StartVertex; Point3d PStart = P.Vertices[vStart].ToPoint3d(); Point3d PEnd = P.Vertices[vEnd].ToPoint3d(); for (int j = 0; j < FC.Count; j++) { double paramS = new double(); double paramE = new double(); Curve thisFC = FC[j]; thisFC.ClosestPoint(PStart, out paramS); thisFC.ClosestPoint(PEnd, out paramE); if ((PStart.DistanceTo(thisFC.PointAt(paramS)) < FixT) && (PEnd.DistanceTo(thisFC.PointAt(paramE)) < FixT)) { FeatureE[FeatureE.Count - 1] = j; } } } #endregion } else { for (int iter = 0; iter < Iters; iter++) { int EdgeCount = P.Halfedges.Count / 2; double[] EdgeLength = P.Halfedges.GetLengths(); List<bool> Visited = new List<bool>(); Vector3d[] Normals = new Vector3d[P.Vertices.Count]; for (int i = 0; i < P.Vertices.Count; i++) { Visited.Add(false); Normals[i] = Normal(P, i); } double t = LengthTol; //a tolerance for when to split/collapse edges double smooth = SmoothStrength; //smoothing strength double pull = PullStrength; //pull to target mesh strength // Split the edges that are too long for (int i = 0; i < EdgeCount; i++) { if (P.Halfedges[2 * i].IsUnused == false) { int vStart = P.Halfedges[2 * i].StartVertex; int vEnd = P.Halfedges[2 * i + 1].StartVertex; if ((Visited[vStart] == false) && (Visited[vEnd] == false)) { double L2 = TargetLength.Calculate(P, 2 * i); if (EdgeLength[2 * i] > (1 + t) * (4f / 3f) * L2) { int SplitHEdge = P.Halfedges.TriangleSplitEdge(2 * i); if (SplitHEdge != -1) { int SplitCenter = P.Halfedges[SplitHEdge].StartVertex; P.Vertices.SetVertex(SplitCenter, MidPt(P, i)); //update the feature information FeatureE.Add(FeatureE[i]); FeatureV.Add(FeatureE[i]); AnchorV.Add(-1); //2 additional new edges have also been created (or 1 if split was on a boundary) //mark these as non-features int CEdgeCount = P.Halfedges.Count / 2; while (FeatureE.Count < CEdgeCount) { FeatureE.Add(-1); } Visited.Add(true); int[] Neighbours = P.Vertices.GetVertexNeighbours(SplitCenter); foreach (int n in Neighbours) { Visited[n] = true; } } } } } } //Collapse the edges that are too short for (int i = 0; i < EdgeCount; i++) { if (P.Halfedges[2 * i].IsUnused == false) { int vStart = P.Halfedges[2 * i].StartVertex; int vEnd = P.Halfedges[2 * i + 1].StartVertex; if ((Visited[vStart] == false) && (Visited[vEnd] == false)) { if (!(AnchorV[vStart] != -1 && AnchorV[vEnd] != -1)) // if both ends are anchored, don't collapse { int Collapse_option = 0; //0 for none, 1 for collapse to midpt, 2 for towards start, 3 for towards end //if neither are anchorV if (AnchorV[vStart] == -1 && AnchorV[vEnd] == -1) { // if both on same feature (or neither on a feature) if (FeatureV[vStart] == FeatureV[vEnd]) { Collapse_option = 1; } // if start is on a feature and end isn't if ((FeatureV[vStart] != -1) && (FeatureV[vEnd] == -1)) { Collapse_option = 2; } // if end is on a feature and start isn't if ((FeatureV[vStart] == -1) && (FeatureV[vEnd] != -1)) { Collapse_option = 3; } } else // so one end must be an anchor { // if start is an anchor if (AnchorV[vStart] != -1) { // if both are on same feature, or if the end is not a feature if ((FeatureE[i] != -1) || (FeatureV[vEnd] == -1)) { Collapse_option = 2; } } // if end is an anchor if (AnchorV[vEnd] != -1) { // if both are on same feature, or if the start is not a feature if ((FeatureE[i] != -1) || (FeatureV[vStart] == -1)) { Collapse_option = 3; } } } Point3d Mid = MidPt(P, i); double L2 = TargetLength.Calculate(P, 2 * i); if ((Collapse_option != 0) && (EdgeLength[2 * i] < (1 - t) * 4f / 5f * L2)) { int Collapsed = -1; int CollapseRtn = -1; if (Collapse_option == 1) { Collapsed = P.Halfedges[2 * i].StartVertex; P.Vertices.SetVertex(Collapsed, MidPt(P, i)); CollapseRtn = P.Halfedges.CollapseEdge(2 * i); } if (Collapse_option == 2) { Collapsed = P.Halfedges[2 * i].StartVertex; CollapseRtn = P.Halfedges.CollapseEdge(2 * i); } if (Collapse_option == 3) { Collapsed = P.Halfedges[2 * i + 1].StartVertex; CollapseRtn = P.Halfedges.CollapseEdge(2 * i + 1); } if (CollapseRtn != -1) { int[] Neighbours = P.Vertices.GetVertexNeighbours(Collapsed); foreach (int n in Neighbours) { Visited[n] = true; } } } } } } } EdgeCount = P.Halfedges.Count / 2; if ((Flip == 0) && (PullStrength > 0)) { //Flip edges to reduce valence error for (int i = 0; i < EdgeCount; i++) { if (!P.Halfedges[2 * i].IsUnused && (P.Halfedges[2 * i].AdjacentFace != -1) && (P.Halfedges[2 * i + 1].AdjacentFace != -1) && (FeatureE[i] == -1) // don't flip feature edges ) { int Vert1 = P.Halfedges[2 * i].StartVertex; int Vert2 = P.Halfedges[2 * i + 1].StartVertex; int Vert3 = P.Halfedges[P.Halfedges[P.Halfedges[2 * i].NextHalfedge].NextHalfedge].StartVertex; int Vert4 = P.Halfedges[P.Halfedges[P.Halfedges[2 * i + 1].NextHalfedge].NextHalfedge].StartVertex; int Valence1 = P.Vertices.GetValence(Vert1); int Valence2 = P.Vertices.GetValence(Vert2); int Valence3 = P.Vertices.GetValence(Vert3); int Valence4 = P.Vertices.GetValence(Vert4); if (P.Vertices.NakedEdgeCount(Vert1) > 0) { Valence1 += 2; } if (P.Vertices.NakedEdgeCount(Vert2) > 0) { Valence2 += 2; } if (P.Vertices.NakedEdgeCount(Vert3) > 0) { Valence3 += 2; } if (P.Vertices.NakedEdgeCount(Vert4) > 0) { Valence4 += 2; } int CurrentError = Math.Abs(Valence1 - 6) + Math.Abs(Valence2 - 6) + Math.Abs(Valence3 - 6) + Math.Abs(Valence4 - 6); int FlippedError = Math.Abs(Valence1 - 7) + Math.Abs(Valence2 - 7) + Math.Abs(Valence3 - 5) + Math.Abs(Valence4 - 5); if (CurrentError > FlippedError) { P.Halfedges.FlipEdge(2 * i); } } } } else { //Flip edges based on angle for (int i = 0; i < EdgeCount; i++) { if (!P.Halfedges[2 * i].IsUnused && (P.Halfedges[2 * i].AdjacentFace != -1) && (P.Halfedges[2 * i + 1].AdjacentFace != -1) && (FeatureE[i] == -1) // don't flip feature edges ) { int Vert1 = P.Halfedges[2 * i].StartVertex; int Vert2 = P.Halfedges[2 * i + 1].StartVertex; int Vert3 = P.Halfedges[P.Halfedges[P.Halfedges[2 * i].NextHalfedge].NextHalfedge].StartVertex; int Vert4 = P.Halfedges[P.Halfedges[P.Halfedges[2 * i + 1].NextHalfedge].NextHalfedge].StartVertex; Point3d P1 = P.Vertices[Vert1].ToPoint3d(); Point3d P2 = P.Vertices[Vert2].ToPoint3d(); Point3d P3 = P.Vertices[Vert3].ToPoint3d(); Point3d P4 = P.Vertices[Vert4].ToPoint3d(); double A1 = Vector3d.VectorAngle(new Vector3d(P3 - P1), new Vector3d(P4 - P1)) + Vector3d.VectorAngle(new Vector3d(P4 - P2), new Vector3d(P3 - P2)); double A2 = Vector3d.VectorAngle(new Vector3d(P1 - P4), new Vector3d(P2 - P4)) + Vector3d.VectorAngle(new Vector3d(P2 - P3), new Vector3d(P1 - P3)); if (A2 > A1) { P.Halfedges.FlipEdge(2 * i); } } } } if (Minim) { Vector3d[] SmoothC = LaplacianSmooth(P, 1, smooth); for (int i = 0; i < P.Vertices.Count; i++) { if (AnchorV[i] == -1) // don't smooth feature vertices { P.Vertices.MoveVertex(i, 0.5 * SmoothC[i]); } } } Vector3d[] Smooth = LaplacianSmooth(P, 0, smooth); for (int i = 0; i < P.Vertices.Count; i++) { if (AnchorV[i] == -1) // don't smooth feature vertices { // make it tangential only Vector3d VNormal = Normal(P, i); double ProjLength = Smooth[i] * VNormal; Smooth[i] = Smooth[i] - (VNormal * ProjLength); P.Vertices.MoveVertex(i, Smooth[i]); if (P.Vertices.NakedEdgeCount(i) != 0)//special smoothing for feature edges { int[] Neighbours = P.Vertices.GetVertexNeighbours(i); int ncount = 0; Point3d Avg = new Point3d(); for (int j = 0; j < Neighbours.Length; j++) { if (P.Vertices.NakedEdgeCount(Neighbours[j]) != 0) { ncount++; Avg = Avg + P.Vertices[Neighbours[j]].ToPoint3d(); } } Avg = Avg * (1.0 / ncount); Vector3d move = Avg - P.Vertices[i].ToPoint3d(); move = move * smooth; P.Vertices.MoveVertex(i, move); } if (FeatureV[i] != -1)//special smoothing for feature edges { int[] Neighbours = P.Vertices.GetVertexNeighbours(i); int ncount = 0; Point3d Avg = new Point3d(); for (int j = 0; j < Neighbours.Length; j++) { if ((FeatureV[Neighbours[j]] == FeatureV[i]) || (AnchorV[Neighbours[j]] != -1)) { ncount++; Avg = Avg + P.Vertices[Neighbours[j]].ToPoint3d(); } } Avg = Avg * (1.0 / ncount); Vector3d move = Avg - P.Vertices[i].ToPoint3d(); move = move * smooth; P.Vertices.MoveVertex(i, move); } //projecting points onto the target along their normals if (pull > 0) { Point3d Point = P.Vertices[i].ToPoint3d(); Vector3d normal = Normal(P, i); Ray3d Ray1 = new Ray3d(Point, normal); Ray3d Ray2 = new Ray3d(Point, -normal); double RayPt1 = Rhino.Geometry.Intersect.Intersection.MeshRay(M, Ray1); double RayPt2 = Rhino.Geometry.Intersect.Intersection.MeshRay(M, Ray2); Point3d ProjectedPt; if ((RayPt1 < RayPt2) && (RayPt1 > 0) && (RayPt1 < 1.0)) { ProjectedPt = Point * (1 - pull) + pull * Ray1.PointAt(RayPt1); } else if ((RayPt2 < RayPt1) && (RayPt2 > 0) && (RayPt2 < 1.0)) { ProjectedPt = Point * (1 - pull) + pull * Ray2.PointAt(RayPt2); } else { ProjectedPt = Point * (1 - pull) + pull * M.ClosestPoint(Point); } P.Vertices.SetVertex(i, ProjectedPt); } if (FeatureV[i] != -1) //pull feature vertices onto feature curves { Point3d Point = P.Vertices[i].ToPoint3d(); Curve CF = FC[FeatureV[i]]; double param1 = 0.0; Point3d onFeature = new Point3d(); CF.ClosestPoint(Point, out param1); onFeature = CF.PointAt(param1); P.Vertices.SetVertex(i, onFeature); } } else { P.Vertices.SetVertex(i, FV[AnchorV[i]]); //pull anchor vertices onto their points } } //end new AnchorV = CompactByVertex(P, AnchorV); //compact the fixed points along with the vertices FeatureV = CompactByVertex(P, FeatureV); FeatureE = CompactByEdge(P, FeatureE); P.Compact(); //this cleans the mesh data structure of unused elements } } DA.SetData(0, P); }
/// <summary> /// Cut a "partial" hole, ie we cut the mesh with the polygon once, and then /// extrude downwards to a planar version of the cut boundary. /// /// Currently only supports extruding downwards from topmost intersection. /// /// </summary> protected bool CutPartialHole(DMesh3 mesh, HoleInfo hi, Vector3d translate, bool bUpwards) { if (hi.IsVertical == false) { throw new Exception("unsupported!"); } Vector3d basePoint = CombinedBounds.Center - CombinedBounds.Extents.y * Vector3d.AxisY + translate; // do we need to compute spatial DS for each hole? not super efficient... DMeshAABBTree3 spatial = new DMeshAABBTree3(mesh, true); Vector3d direction = (bUpwards) ? Vector3d.AxisY : -Vector3d.AxisY; Vector3d center = basePoint + new Vector3d(hi.XZOffset.x, 0, hi.XZOffset.y) - 10000 * direction; Ray3d ray = new Ray3d(center, direction); int hit_tid = spatial.FindNearestHitTriangle(ray); if (hit_tid == DMesh3.InvalidID) { return(false); } IntrRay3Triangle3 intersection = MeshQueries.TriangleIntersection(mesh, hit_tid, ray); Vector3d inter_pos = ray.PointAt(intersection.RayParameter); Frame3f projectFrame = new Frame3f(ray.Origin, ray.Direction); int nVerts = 32; if (hi.Vertices != 0) { nVerts = hi.Vertices; } double angleShiftRad = hi.AxisAngleD * MathUtil.Deg2Rad; Polygon2d circle = Polygon2d.MakeCircle(hi.Radius, nVerts, angleShiftRad); try { EdgeLoop loop = null; MeshInsertProjectedPolygon insert = new MeshInsertProjectedPolygon(mesh, circle, projectFrame, hit_tid) { SimplifyInsertion = false }; if (insert.Insert()) { loop = insert.InsertedLoop; // [RMS] do we need to simplify for this one? //if (loop.VertexCount > circle.VertexCount) // loop = simplify_loop(mesh, loop, circle.VertexCount); MeshEditor editor = new MeshEditor(mesh); Vector3d base_pos = inter_pos; base_pos.y = basePoint.y + hi.PartialHoleBaseHeight; int N = loop.VertexCount; int[] newLoop = new int[N]; for (int k = 0; k < N; ++k) { newLoop[k] = mesh.AppendVertex(mesh, loop.Vertices[k]); Vector3d cur_v = mesh.GetVertex(newLoop[k]); cur_v.y = base_pos.y; mesh.SetVertex(newLoop[k], cur_v); } int base_vid = mesh.AppendVertex(base_pos); int[] fan_tris = editor.AddTriangleFan_OrderedVertexLoop(base_vid, newLoop); FaceGroupUtil.SetGroupID(mesh, fan_tris, hi.PartialHoleGroupID); int[] stitch_tris = editor.StitchLoop(loop.Vertices, newLoop); // need to remesh fan region because otherwise we get pathological cases RegionRemesher remesh = new RegionRemesher(mesh, fan_tris); remesh.SetTargetEdgeLength(2.0); remesh.SmoothSpeedT = 1.0; remesh.PreventNormalFlips = true; for (int k = 0; k < 25; ++k) { remesh.BasicRemeshPass(); } //remesh.EnableCollapses = remesh.EnableFlips = remesh.EnableSplits = false; //for (int k = 0; k < 20; ++k) // remesh.BasicRemeshPass(); remesh.BackPropropagate(); return(true); } else { return(false); } } catch (Exception e) { f3.DebugUtil.Log("partial hole {0} failed!! {1}", hi.nHole, e.Message); return(false); } }
protected override void SolveInstance(IGH_DataAccess DA) { Point3d person = new Point3d(0, 0, 0); int angle = 0; Vector3d direction = new Vector3d(0, 0, 0); double viewDistance = 0; List <Mesh> obstacles = new List <Mesh>(); List <Ray3d> viewRays = new List <Ray3d>(); List <Point3d> Rayhits = new List <Point3d>(); int fovfree = 0; Mesh meshes = new Mesh(); DA.GetData(0, ref person); DA.GetData(1, ref direction); DA.GetData(2, ref viewDistance); DA.GetData(3, ref angle); DA.GetDataList(4, obstacles); int viewRes = angle; foreach (Mesh mesh in obstacles) { meshes.Append(mesh); } direction.Z = 0; direction.Rotate(Rhino.RhinoMath.ToRadians(angle / 2), new Vector3d(0, 0, 1)); Line viewAngleA = new Line(person, direction, viewDistance); direction.Rotate(-Rhino.RhinoMath.ToRadians(angle / 2) * 2, new Vector3d(0, 0, 1)); Line viewAngleB = new Line(person, direction, viewDistance); List <Line> Liness = new List <Line>(); Liness.Add(viewAngleA); Liness.Add(viewAngleB); for (int i = 0; i < viewRes + 2; i++) { if (i > 1) { direction.Rotate(Rhino.RhinoMath.ToRadians((angle / viewRes)), new Vector3d(0, 0, 1)); } Ray3d ray = new Ray3d(person, direction); double rayT = Rhino.Geometry.Intersect.Intersection.MeshRay(meshes, ray); Vector3d newvec = Rhino.Geometry.Vector3d.Multiply(direction, viewDistance); if (rayT > 0) { if (person.DistanceTo(ray.PointAt(rayT)) < viewDistance) { Rayhits.Add(ray.PointAt(rayT)); } else { Rayhits.Add(new Point3d(newvec.X + person.X, newvec.Y + person.Y, person.Z)); fovfree = fovfree + 1; } } else { Rayhits.Add(new Point3d(newvec.X + person.X, newvec.Y + person.Y, person.Z)); fovfree = fovfree + 1; } } Mesh viewMesh = new Mesh(); viewMesh.Vertices.UseDoublePrecisionVertices = true; //Make mesh from hitspoints viewMesh.Vertices.Add(new Point3f((float)person.X, (float)person.Y, (float)person.Z)); viewMesh.VertexColors.Add(System.Drawing.Color.Ivory); for (int i = 0; i < Rayhits.Count; i++) { viewMesh.Vertices.Add(new Point3f((float)Rayhits[i].X, (float)Rayhits[i].Y, (float)Rayhits[i].Z)); viewMesh.VertexColors.Add(System.Drawing.Color.Ivory); } for (int i = 0; i < (viewRes + 2); i++) { viewMesh.Faces.AddFace(0, i, i + 1); } viewMesh.Faces.RemoveAt(0); DA.SetData(0, viewMesh); DA.SetData(1, fovfree); }
public static GH_Mesh ProjectMeshToTopoSlow(Mesh topoMesh, Mesh topoFlatMesh, Point3d[] topoFlatPoints, RTree rTree, Mesh featureMesh) { ///TODO: Look into using Mesh.SplitWithProjectedPolylines available in RhinoCommon 7.0 GH_Mesh ghMesh = new GH_Mesh(); Mesh[] disjointMeshes = featureMesh.SplitDisjointPieces(); Mesh projectedDisjointMeshes = new Mesh(); foreach (Mesh disjointMesh in disjointMeshes) { ///Flatten disjointMesh first for (int i = 0; i < disjointMesh.Vertices.Count; i++) { Point3f v = disjointMesh.Vertices[i]; v.Z = 0; disjointMesh.Vertices.SetVertex(i, v); } ///Get naked edges and sort list so that outer boundary is first Polyline[] nakedEdges = disjointMesh.GetNakedEdges(); var nakedEdgesCurves = new Dictionary <Curve, double>(); foreach (Polyline p in nakedEdges) { Curve pNurbs = p.ToNurbsCurve(); nakedEdgesCurves.Add(pNurbs, AreaMassProperties.Compute(pNurbs).Area); } var nakedEdgesSorted = from pair in nakedEdgesCurves orderby pair.Value descending select pair.Key; BoundingBox bbox = disjointMesh.GetBoundingBox(false); ///Project naked edges to flat topo to add control points at mesh edge intersections List <Curve> trimCurves = new List <Curve>(); foreach (Curve nakedEdge in nakedEdgesSorted) { Curve[] projectedCurves = Curve.ProjectToMesh(nakedEdge, topoFlatMesh, moveDir, tol); ///If projection of naked edge results in more than one curve, join curves back into one closed curve. ///Approximation at edge of topo is unavoidable if (projectedCurves.Length > 0) { if (projectedCurves.Length > 1) { ///Collector polyline to combine projectedCurves Polyline projBoundary = new Polyline(); ///Add individual curves from Curve.ProjectToMesh together by converting to Polyline and appending the vetexes together foreach (Curve c in projectedCurves) { Polyline tempPolyline = new Polyline(); c.TryGetPolyline(out tempPolyline); projBoundary.AddRange(tempPolyline); } ///Make sure polyine is closed projBoundary.Add(projBoundary[0]); trimCurves.Add(projBoundary.ToNurbsCurve()); } else if (!projectedCurves[0].IsClosed) { Line closer = new Line(projectedCurves[0].PointAtEnd, projectedCurves[0].PointAtStart); Curve closedProjectedCurve = Curve.JoinCurves(new Curve[] { projectedCurves[0], closer.ToNurbsCurve() })[0]; trimCurves.Add(closedProjectedCurve); } else { trimCurves.Add(projectedCurves[0]); } } else { ///Projection missed the topoFlatMesh return(null); } } ///End projected naked edges Polyline pL = new Polyline(); trimCurves[0].TryGetPolyline(out pL); trimCurves.RemoveAt(0); ///Add points from topoMeshFlat to array used for Mesh.CreatePatch List <Point3f> bboxPoints = new List <Point3f>(); ///Try RTree method. RTree of topoFlatPoints ///https://discourse.mcneel.com/t/rtree-bounding-box-search/96282/6 var boxSearchData = new BoxSearchData(); rTree.Search(bbox, BoundingBoxCallback, boxSearchData); foreach (int id in boxSearchData.Ids) { Ray3d ray = new Ray3d((Point3d)topoFlatPoints[id], -moveDir); double t = Rhino.Geometry.Intersect.Intersection.MeshRay(disjointMesh, ray); if (t >= 0.0) { bboxPoints.Add((Point3f)ray.PointAt(t)); } else { Ray3d rayOpp = new Ray3d((Point3d)topoFlatPoints[id], moveDir); double tOpp = Rhino.Geometry.Intersect.Intersection.MeshRay(disjointMesh, rayOpp); if (tOpp >= 0.0) { bboxPoints.Add((Point3f)rayOpp.PointAt(tOpp)); } else { //return null; } } } ///A hack way of adding points to newVerts which is needed in the form of an array for Mesh.CreatePatch disjointMesh.Vertices.AddVertices(bboxPoints); Point3d[] newVerts = disjointMesh.Vertices.ToPoint3dArray(); ///Create patch Mesh mPatch = Mesh.CreatePatch(pL, tol, null, trimCurves, null, newVerts, true, 1); ///Move patch verts to topo for (int i = 0; i < mPatch.Vertices.Count; i++) { Ray3d ray = new Ray3d((Point3d)mPatch.Vertices[i], moveDir); double t = Rhino.Geometry.Intersect.Intersection.MeshRay(topoMesh, ray); if (t >= 0.0) { mPatch.Vertices.SetVertex(i, (Point3f)ray.PointAt(t)); } else { Ray3d rayOpp = new Ray3d((Point3d)mPatch.Vertices[i], -moveDir); double tOpp = Rhino.Geometry.Intersect.Intersection.MeshRay(topoMesh, rayOpp); if (tOpp >= 0.0) { mPatch.Vertices.SetVertex(i, (Point3f)rayOpp.PointAt(tOpp)); } else { return(null); } } } ///Combine disjoint meshes if (mPatch.IsValid) { projectedDisjointMeshes.Append(mPatch); mPatch.Dispose(); } else { return(null); } } projectedDisjointMeshes.Ngons.AddPlanarNgons(tol); projectedDisjointMeshes.Compact(); GH_Convert.ToGHMesh(projectedDisjointMeshes, GH_Conversion.Primary, ref ghMesh); return(ghMesh); }
protected override Result RunCommand(RhinoDoc doc, RunMode mode) { // TODO: start here modifying the behaviour of your command. // --- RhinoApp.WriteLine("MeshMachine WIP test", EnglishName); Brep SB; using (GetObject getBrep = new GetObject()) { getBrep.SetCommandPrompt("Please select the brep to remesh"); getBrep.Get(); SB = getBrep.Object(0).Brep(); } //GetNumber TargetLength = new GetNumber(); //double L = TargetLength.Number(); Rhino.Input.Custom.GetNumber gn = new Rhino.Input.Custom.GetNumber(); gn.SetCommandPrompt("Specify a Target Edge Length"); gn.SetLowerLimit(0.5, false); gn.Get(); if (gn.CommandResult() != Rhino.Commands.Result.Success) { return(gn.CommandResult()); } double L = gn.Number(); //Point3d pt0; //using (GetPoint getPointAction = new GetPoint()) //{ // getPointAction.SetCommandPrompt("Please select the start point"); // if (getPointAction.Get() != GetResult.Point) // { // RhinoApp.WriteLine("No start point was selected."); // return getPointAction.CommandResult(); // } // pt0 = getPointAction.Point(); //} //Point3d pt1; //using (GetPoint getPointAction = new GetPoint()) //{ // getPointAction.SetCommandPrompt("Please select the end point"); // getPointAction.SetBasePoint(pt0, true); // getPointAction.DynamicDraw += // (sender, e) => e.Display.DrawLine(pt0, e.CurrentPoint, System.Drawing.Color.DarkRed); // if (getPointAction.Get() != GetResult.Point) // { // RhinoApp.WriteLine("No end point was selected."); // return getPointAction.CommandResult(); // } // pt1 = getPointAction.Point(); //} //doc.Objects.AddLine(pt0, pt1); PlanktonMesh P = new PlanktonMesh(); List <int> AnchorV = new List <int>(); List <int> FeatureV = new List <int>(); List <int> FeatureE = new List <int>(); double FixT = 0.00001; double LengthTol = 0.15; //a tolerance for when to split/collapse edges double SmoothStrength = 0.8; //smoothing strength double PullStrength = 0.8; //pull to target mesh strength double CurvDep = 0; int Flip = 1; MeshingParameters MeshParams = new MeshingParameters(); MeshParams.MaximumEdgeLength = 3 * L; MeshParams.MinimumEdgeLength = L; MeshParams.JaggedSeams = false; MeshParams.SimplePlanes = false; Mesh[] BrepMeshes = Mesh.CreateFromBrep(SB, MeshParams); Mesh M = new Mesh(); foreach (var mesh in BrepMeshes) { M.Append(mesh); } M.Faces.ConvertQuadsToTriangles(); P = M.ToPlanktonMesh(); var FC = new List <Curve>(); foreach (BrepEdge E in SB.Edges) { if (!E.IsSmoothManifoldEdge(0.01)) { FC.Add(E.ToNurbsCurve()); } } var Corners = SB.Vertices; List <Point3d> FV = new List <Point3d>(); foreach (Point Pt in Corners) { FV.Add(Pt.Location); } //Mark any vertices or edges lying on features for (int i = 0; i < P.Vertices.Count; i++) { Point3d Pt = P.Vertices[i].ToPoint3d(); AnchorV.Add(-1); for (int j = 0; j < FV.Count; j++) { if (Pt.DistanceTo(FV[j]) < FixT) { AnchorV[AnchorV.Count - 1] = j; } } FeatureV.Add(-1); for (int j = 0; j < FC.Count; j++) { double param = new double(); FC[j].ClosestPoint(Pt, out param); if (Pt.DistanceTo(FC[j].PointAt(param)) < FixT) { FeatureV[FeatureV.Count - 1] = j; } } } int EdgeCount = P.Halfedges.Count / 2; for (int i = 0; i < EdgeCount; i++) { FeatureE.Add(-1); int vStart = P.Halfedges[2 * i].StartVertex; int vEnd = P.Halfedges[2 * i + 1].StartVertex; Point3d PStart = P.Vertices[vStart].ToPoint3d(); Point3d PEnd = P.Vertices[vEnd].ToPoint3d(); for (int j = 0; j < FC.Count; j++) { double paramS = new double(); double paramE = new double(); Curve thisFC = FC[j]; thisFC.ClosestPoint(PStart, out paramS); thisFC.ClosestPoint(PEnd, out paramE); if ((PStart.DistanceTo(thisFC.PointAt(paramS)) < FixT) && (PEnd.DistanceTo(thisFC.PointAt(paramE)) < FixT)) { FeatureE[FeatureE.Count - 1] = j; } } } for (int iter = 0; iter < 30; iter++) { EdgeCount = P.Halfedges.Count / 2; double[] EdgeLength = P.Halfedges.GetLengths(); List <bool> Visited = new List <bool>(); Vector3d[] Normals = new Vector3d[P.Vertices.Count]; for (int i = 0; i < P.Vertices.Count; i++) { Visited.Add(false); Normals[i] = Util.Normal(P, i); } double t = LengthTol; //a tolerance for when to split/collapse edges double smooth = SmoothStrength; //smoothing strength double pull = PullStrength; //pull to target mesh strength // Split the edges that are too long for (int i = 0; i < EdgeCount; i++) { if (P.Halfedges[2 * i].IsUnused == false) { int vStart = P.Halfedges[2 * i].StartVertex; int vEnd = P.Halfedges[2 * i + 1].StartVertex; if ((Visited[vStart] == false) && (Visited[vEnd] == false)) { double L2 = L; Point3d Mid = Util.MidPt(P, i); //if (CurvDep > 0) //{ // double NormDiff = Vector3d.VectorAngle(Normals[vStart], Normals[vEnd]); // L2 = Math.Min((1.0 / (3.0 * NormDiff) * L), 5 * L); // if (CurvDep != 1) // { // L2 = L2 * (CurvDep) + L * (1.0 - CurvDep); // } //} //if (BoundScale != 1.0) //{ // double MinDist = 99954; // for (int j = 0; j < FC.Count; j++) // { // double param = new double(); // FC[j].ClosestPoint(Mid, out param); // double ThisDist = Mid.DistanceTo(FC[j].PointAt(param)); // if (ThisDist < MinDist) // { MinDist = ThisDist; } // } // if (MinDist < BoundDist) // { // L2 = L2 * BoundScale + (MinDist / BoundDist) * (L2 * (1 - BoundScale)); // } //} //if (SizP.Count > 0) //{ // L2 = WeightedCombo(Mid, SizP, SizV, WExp, L2, BGW); // // L2 = (WL * (1.0 - BGW)) + (BGW * L2); //} if (EdgeLength[2 * i] > (1 + t) * (4f / 3f) * L2) { int SplitHEdge = P.Halfedges.TriangleSplitEdge(2 * i); if (SplitHEdge != -1) { int SplitCenter = P.Halfedges[SplitHEdge].StartVertex; P.Vertices.SetVertex(SplitCenter, Util.MidPt(P, i)); //update the feature information FeatureE.Add(FeatureE[i]); FeatureV.Add(FeatureE[i]); AnchorV.Add(-1); //2 additional new edges have also been created (or 1 if split was on a boundary) //mark these as non-features int CEdgeCount = P.Halfedges.Count / 2; while (FeatureE.Count < CEdgeCount) { FeatureE.Add(-1); } Visited.Add(true); int[] Neighbours = P.Vertices.GetVertexNeighbours(SplitCenter); foreach (int n in Neighbours) { Visited[n] = true; } } } } } } //Collapse the edges that are too short for (int i = 0; i < EdgeCount; i++) { if (P.Halfedges[2 * i].IsUnused == false) { int vStart = P.Halfedges[2 * i].StartVertex; int vEnd = P.Halfedges[2 * i + 1].StartVertex; if ((Visited[vStart] == false) && (Visited[vEnd] == false)) { if (!(AnchorV[vStart] != -1 && AnchorV[vEnd] != -1)) // if both ends are anchored, don't collapse { int Collapse_option = 0; //0 for none, 1 for collapse to midpt, 2 for towards start, 3 for towards end //if neither are anchorV if (AnchorV[vStart] == -1 && AnchorV[vEnd] == -1) { // if both on same feature (or neither on a feature) if (FeatureV[vStart] == FeatureV[vEnd]) { Collapse_option = 1; } // if start is on a feature and end isn't if ((FeatureV[vStart] != -1) && (FeatureV[vEnd] == -1)) { Collapse_option = 2; } // if end is on a feature and start isn't if ((FeatureV[vStart] == -1) && (FeatureV[vEnd] != -1)) { Collapse_option = 3; } } else // so one end must be an anchor { // if start is an anchor if (AnchorV[vStart] != -1) { // if both are on same feature, or if the end is not a feature if ((FeatureE[i] != -1) || (FeatureV[vEnd] == -1)) { Collapse_option = 2; } } // if end is an anchor if (AnchorV[vEnd] != -1) { // if both are on same feature, or if the start is not a feature if ((FeatureE[i] != -1) || (FeatureV[vStart] == -1)) { Collapse_option = 3; } } } double L2 = L; Point3d Mid = Util.MidPt(P, i); if (CurvDep > 0) { double NormDiff = Vector3d.VectorAngle(Normals[vStart], Normals[vEnd]); L2 = Math.Min((1.0 / (3.0 * NormDiff) * L), 5 * L); if (CurvDep != 1) { L2 = L2 * (CurvDep) + L * (1.0 - CurvDep); } } //if (BoundScale != 1.0) //{ // double MinDist = 99954; // for (int j = 0; j < FC.Count; j++) // { // double param = new double(); // FC[j].ClosestPoint(Mid, out param); // double ThisDist = Mid.DistanceTo(FC[j].PointAt(param)); // if (ThisDist < MinDist) // { MinDist = ThisDist; } // } // if (MinDist < BoundDist) // { // L2 = L2 * BoundScale + (MinDist / BoundDist) * (L2 * (1 - BoundScale)); // } //} //if (SizP.Count > 0) //{ // L2 = WeightedCombo(Mid, SizP, SizV, WExp, L2, BGW); // //double WL = WeightedCombo(Mid, SizP, SizV, WExp); // //L2 = (WL * (1.0 - BGW)) + (BGW * L2); //} if ((Collapse_option != 0) && (EdgeLength[2 * i] < (1 - t) * 4f / 5f * L2)) { int Collapsed = -1; int CollapseRtn = -1; if (Collapse_option == 1) { Collapsed = P.Halfedges[2 * i].StartVertex; P.Vertices.SetVertex(Collapsed, Util.MidPt(P, i)); CollapseRtn = P.Halfedges.CollapseEdge(2 * i); } if (Collapse_option == 2) { Collapsed = P.Halfedges[2 * i].StartVertex; CollapseRtn = P.Halfedges.CollapseEdge(2 * i); } if (Collapse_option == 3) { Collapsed = P.Halfedges[2 * i + 1].StartVertex; CollapseRtn = P.Halfedges.CollapseEdge(2 * i + 1); } if (CollapseRtn != -1) { int[] Neighbours = P.Vertices.GetVertexNeighbours(Collapsed); foreach (int n in Neighbours) { Visited[n] = true; } } } } } } } EdgeCount = P.Halfedges.Count / 2; if ((Flip == 0) && (PullStrength > 0)) { //Flip edges to reduce valence error for (int i = 0; i < EdgeCount; i++) { if (!P.Halfedges[2 * i].IsUnused && (P.Halfedges[2 * i].AdjacentFace != -1) && (P.Halfedges[2 * i + 1].AdjacentFace != -1) && (FeatureE[i] == -1) // don't flip feature edges ) { int Vert1 = P.Halfedges[2 * i].StartVertex; int Vert2 = P.Halfedges[2 * i + 1].StartVertex; int Vert3 = P.Halfedges[P.Halfedges[P.Halfedges[2 * i].NextHalfedge].NextHalfedge].StartVertex; int Vert4 = P.Halfedges[P.Halfedges[P.Halfedges[2 * i + 1].NextHalfedge].NextHalfedge].StartVertex; int Valence1 = P.Vertices.GetValence(Vert1); int Valence2 = P.Vertices.GetValence(Vert2); int Valence3 = P.Vertices.GetValence(Vert3); int Valence4 = P.Vertices.GetValence(Vert4); if (P.Vertices.NakedEdgeCount(Vert1) > 0) { Valence1 += 2; } if (P.Vertices.NakedEdgeCount(Vert2) > 0) { Valence2 += 2; } if (P.Vertices.NakedEdgeCount(Vert3) > 0) { Valence3 += 2; } if (P.Vertices.NakedEdgeCount(Vert4) > 0) { Valence4 += 2; } int CurrentError = Math.Abs(Valence1 - 6) + Math.Abs(Valence2 - 6) + Math.Abs(Valence3 - 6) + Math.Abs(Valence4 - 6); int FlippedError = Math.Abs(Valence1 - 7) + Math.Abs(Valence2 - 7) + Math.Abs(Valence3 - 5) + Math.Abs(Valence4 - 5); if (CurrentError > FlippedError) { P.Halfedges.FlipEdge(2 * i); } } } } else { //Flip edges based on angle for (int i = 0; i < EdgeCount; i++) { if (!P.Halfedges[2 * i].IsUnused && (P.Halfedges[2 * i].AdjacentFace != -1) && (P.Halfedges[2 * i + 1].AdjacentFace != -1) && (FeatureE[i] == -1) // don't flip feature edges ) { int Vert1 = P.Halfedges[2 * i].StartVertex; int Vert2 = P.Halfedges[2 * i + 1].StartVertex; int Vert3 = P.Halfedges[P.Halfedges[P.Halfedges[2 * i].NextHalfedge].NextHalfedge].StartVertex; int Vert4 = P.Halfedges[P.Halfedges[P.Halfedges[2 * i + 1].NextHalfedge].NextHalfedge].StartVertex; Point3d P1 = P.Vertices[Vert1].ToPoint3d(); Point3d P2 = P.Vertices[Vert2].ToPoint3d(); Point3d P3 = P.Vertices[Vert3].ToPoint3d(); Point3d P4 = P.Vertices[Vert4].ToPoint3d(); double A1 = Vector3d.VectorAngle(new Vector3d(P3 - P1), new Vector3d(P4 - P1)) + Vector3d.VectorAngle(new Vector3d(P4 - P2), new Vector3d(P3 - P2)); double A2 = Vector3d.VectorAngle(new Vector3d(P1 - P4), new Vector3d(P2 - P4)) + Vector3d.VectorAngle(new Vector3d(P2 - P3), new Vector3d(P1 - P3)); if (A2 > A1) { P.Halfedges.FlipEdge(2 * i); } } } } //if (Minim) //{ // Vector3d[] SmoothC = LaplacianSmooth(P, 1, smooth); // for (int i = 0; i < P.Vertices.Count; i++) // { // if (AnchorV[i] == -1) // don't smooth feature vertices // { // P.Vertices.MoveVertex(i, 0.5 * SmoothC[i]); // } // } //} Vector3d[] Smooth = Util.LaplacianSmooth(P, 0, smooth); for (int i = 0; i < P.Vertices.Count; i++) { if (AnchorV[i] == -1) // don't smooth feature vertices { // make it tangential only Vector3d VNormal = Util.Normal(P, i); double ProjLength = Smooth[i] * VNormal; Smooth[i] = Smooth[i] - (VNormal * ProjLength); P.Vertices.MoveVertex(i, Smooth[i]); if (P.Vertices.NakedEdgeCount(i) != 0)//special smoothing for feature edges { int[] Neighbours = P.Vertices.GetVertexNeighbours(i); int ncount = 0; Point3d Avg = new Point3d(); for (int j = 0; j < Neighbours.Length; j++) { if (P.Vertices.NakedEdgeCount(Neighbours[j]) != 0) { ncount++; Avg = Avg + P.Vertices[Neighbours[j]].ToPoint3d(); } } Avg = Avg * (1.0 / ncount); Vector3d move = Avg - P.Vertices[i].ToPoint3d(); move = move * smooth; P.Vertices.MoveVertex(i, move); } if (FeatureV[i] != -1)//special smoothing for feature edges { int[] Neighbours = P.Vertices.GetVertexNeighbours(i); int ncount = 0; Point3d Avg = new Point3d(); for (int j = 0; j < Neighbours.Length; j++) { if ((FeatureV[Neighbours[j]] == FeatureV[i]) || (AnchorV[Neighbours[j]] != -1)) { ncount++; Avg = Avg + P.Vertices[Neighbours[j]].ToPoint3d(); } } Avg = Avg * (1.0 / ncount); Vector3d move = Avg - P.Vertices[i].ToPoint3d(); move = move * smooth; P.Vertices.MoveVertex(i, move); } //projecting points onto the target along their normals if (pull > 0) { Point3d Point = P.Vertices[i].ToPoint3d(); Vector3d normal = Util.Normal(P, i); Ray3d Ray1 = new Ray3d(Point, normal); Ray3d Ray2 = new Ray3d(Point, -normal); double RayPt1 = Rhino.Geometry.Intersect.Intersection.MeshRay(M, Ray1); double RayPt2 = Rhino.Geometry.Intersect.Intersection.MeshRay(M, Ray2); Point3d ProjectedPt; if ((RayPt1 < RayPt2) && (RayPt1 > 0) && (RayPt1 < 1.0)) { ProjectedPt = Point * (1 - pull) + pull * Ray1.PointAt(RayPt1); } else if ((RayPt2 < RayPt1) && (RayPt2 > 0) && (RayPt2 < 1.0)) { ProjectedPt = Point * (1 - pull) + pull * Ray2.PointAt(RayPt2); } else { ProjectedPt = Point * (1 - pull) + pull * M.ClosestPoint(Point); } P.Vertices.SetVertex(i, ProjectedPt); } if (FeatureV[i] != -1) //pull feature vertices onto feature curves { Point3d Point = P.Vertices[i].ToPoint3d(); Curve CF = FC[FeatureV[i]]; double param1 = 0.0; Point3d onFeature = new Point3d(); CF.ClosestPoint(Point, out param1); onFeature = CF.PointAt(param1); P.Vertices.SetVertex(i, onFeature); } } else { P.Vertices.SetVertex(i, FV[AnchorV[i]]); //pull anchor vertices onto their points } } AnchorV = Util.CompactByVertex(P, AnchorV); //compact the fixed points along with the vertices FeatureV = Util.CompactByVertex(P, FeatureV); FeatureE = Util.CompactByEdge(P, FeatureE); P.Compact(); //this cleans the mesh data structure of unused elements } Mesh MR = P.ToRhinoMesh(); MR.Unweld(0.4, true); doc.Objects.AddMesh(MR); doc.Views.Redraw(); RhinoApp.WriteLine("The {0} command added one mesh to the document.", EnglishName); // --- return(Result.Success); }
/// <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) { List <Plane> camPlanes = new List <Plane>(); DA.GetDataList <Plane>(0, camPlanes); string folder = string.Empty; DA.GetData <string>(1, ref folder); bool saveCubemaps = !string.IsNullOrEmpty(folder); if (saveCubemaps) { folder = Path.GetFullPath(folder); if (!folder.EndsWith(Path.DirectorySeparatorChar.ToString())) { folder += Path.DirectorySeparatorChar; } } string prefix = string.Empty; DA.GetData <string>(2, ref prefix); int imageWidth = 0; DA.GetData <int>(3, ref imageWidth); imageWidth = imageWidth / 4; Size size = new Size(imageWidth, imageWidth); string displayMode = string.Empty; DA.GetData <string>(4, ref displayMode); List <Color> colors = new List <Color>(); DA.GetDataList <Color>(5, colors); bool filterColors = colors.Any(); GH_Structure <GH_Mesh> ghObstacles = new GH_Structure <GH_Mesh>(); DA.GetDataTree <GH_Mesh>(6, out ghObstacles); ///Flatten obstacle meshes and join them into one mesh ghObstacles.FlattenData(); Mesh obstacles = new Mesh(); bool showRays = false; if (ghObstacles.DataCount > 0) { showRays = true; foreach (var obstacle in ghObstacles) { Mesh temp = new Mesh(); GH_Convert.ToMesh(obstacle, ref temp, GH_Conversion.Primary); obstacles.Append(temp); } } bool run = false; DA.GetData <bool>(7, ref run); int pad = camPlanes.Count.ToString().Length; List <string> cubemaps = new List <string>(); GH_Structure <GH_Line> rayTree = new GH_Structure <GH_Line>(); GH_Structure <GH_Colour> colorTree = new GH_Structure <GH_Colour>(); ///Save the intial camera saveCam = camFromVP(Rhino.RhinoDoc.ActiveDoc.Views.ActiveView.ActiveViewport); ///Set the display mode to be used for bitmaps ///TODO: Add menu item to use "Heron View Analysis" display mode DisplayModeDescription viewMode = Rhino.RhinoDoc.ActiveDoc.Views.ActiveView.ActiveViewport.DisplayMode; if (DisplayModeDescription.FindByName(displayMode) != null) { viewMode = DisplayModeDescription.FindByName(displayMode); } Message = viewMode.EnglishName; if (run) { for (int i = 0; i < camPlanes.Count; i++) { ///TODO: setup ability to save cameras to the Rhino doc ///Setup camera Rhino.Display.RhinoView view = Rhino.RhinoDoc.ActiveDoc.Views.ActiveView; Rhino.Display.RhinoViewport vp = view.ActiveViewport; ///Get the bounding box of all visible object in the doc for use in setting up the camera ///target so that the far frustrum plane doesn't clip anything double zoomDistance = Rhino.RhinoDoc.ActiveDoc.Objects.BoundingBoxVisible.Diagonal.Length; Plane camPlane = camPlanes[i]; Point3d camPoint = camPlane.Origin; Vector3d camDir = camPlane.YAxis; Point3d tarPoint = Transform.Translation(camDir * zoomDistance / 2) * camPoint; vp.ChangeToPerspectiveProjection(false, 12.0); vp.Size = size; vp.DisplayMode = viewMode; //view.Redraw(); ///Set up final bitmap Bitmap cubemap = new Bitmap(imageWidth * 4, imageWidth * 3); ///Place the images on cubemap bitmap using (Graphics gr = Graphics.FromImage(cubemap)) { ///Grab bitmap ///Set up camera directions Point3d tarLeft = Transform.Translation(-camPlane.XAxis * zoomDistance / 2) * camPoint; Point3d tarFront = Transform.Translation(camPlane.YAxis * zoomDistance / 2) * camPoint; Point3d tarRight = Transform.Translation(camPlane.XAxis * zoomDistance / 2) * camPoint; Point3d tarBack = Transform.Translation(-camPlane.YAxis * zoomDistance / 2) * camPoint; Point3d tarUp = Transform.Translation(camPlane.ZAxis * zoomDistance / 2) * camPoint; Point3d tarDown = Transform.Translation(-camPlane.ZAxis * zoomDistance / 2) * camPoint; List <Point3d> camTargets = new List <Point3d>() { tarLeft, tarFront, tarRight, tarBack, tarUp, tarDown }; ///Loop through pano directions int insertLoc = 0; for (int d = 0; d < 4; d++) { ///Set camera direction vp.SetCameraLocations(camTargets[d], camPoint); //view.Redraw(); Bitmap bitmap = new Bitmap(view.CaptureToBitmap(size, viewMode)); if (saveCubemaps) { gr.DrawImage(bitmap, insertLoc, imageWidth); } if (showRays) { GH_MemoryBitmap sampler = new GH_MemoryBitmap(bitmap); Color col = Color.Transparent; for (int x = 0; x < bitmap.Width; x++) { for (int y = 0; y < bitmap.Height; y++) { if (sampler.Sample(x, y, ref col)) { if (colors.Contains(col)) { GH_Path path = new GH_Path(i, colors.IndexOf(col)); Line line = vp.ClientToWorld(new System.Drawing.Point(x, y)); Ray3d ray = new Ray3d(vp.CameraLocation, -line.Direction); double rayEnd = (double)Rhino.Geometry.Intersect.Intersection.MeshRay(obstacles, ray); Point3d rayIntersection = ray.PointAt(rayEnd); Line ln = new Line(camPoint, rayIntersection); if (ln.IsValid & rayEnd > 0) { rayTree.Append(new GH_Line(ln), path); colorTree.Append(new GH_Colour(col), path); } } else if (!filterColors) { colors.Add(col); GH_Path path = new GH_Path(i, colors.IndexOf(col)); Line line = vp.ClientToWorld(new System.Drawing.Point(x, y)); Ray3d ray = new Ray3d(vp.CameraLocation, -line.Direction); double rayEnd = (double)Rhino.Geometry.Intersect.Intersection.MeshRay(obstacles, ray); Point3d rayIntersection = ray.PointAt(rayEnd); Line ln = new Line(camPoint, rayIntersection); if (ln.IsValid & rayEnd > 0) { rayTree.Append(new GH_Line(ln), path); colorTree.Append(new GH_Colour(col), path); } } } } } sampler.Release(false); } insertLoc = insertLoc + imageWidth; bitmap.Dispose(); } ///Get up and down views ///Get up view vp.SetCameraLocations(tarUp, camPoint); view.Redraw(); Bitmap bitmapUp = new Bitmap(view.CaptureToBitmap(size, viewMode)); if (showRays) { GH_MemoryBitmap sampler = new GH_MemoryBitmap(bitmapUp); Color col = Color.Transparent; for (int x = 0; x < bitmapUp.Width; x++) { for (int y = 0; y < bitmapUp.Height; y++) { if (sampler.Sample(x, y, ref col)) { if (colors.Contains(col)) { GH_Path path = new GH_Path(i, colors.IndexOf(col)); Line line = vp.ClientToWorld(new System.Drawing.Point(x, y)); Ray3d ray = new Ray3d(vp.CameraLocation, -line.Direction); double rayEnd = (double)Rhino.Geometry.Intersect.Intersection.MeshRay(obstacles, ray); Point3d rayIntersection = ray.PointAt(rayEnd); Line ln = new Line(camPoint, rayIntersection); if (ln.IsValid & rayEnd > 0) { rayTree.Append(new GH_Line(ln), path); colorTree.Append(new GH_Colour(col), path); } } else if (!filterColors) { colors.Add(col); GH_Path path = new GH_Path(i, colors.IndexOf(col)); Line line = vp.ClientToWorld(new System.Drawing.Point(x, y)); Ray3d ray = new Ray3d(vp.CameraLocation, -line.Direction); double rayEnd = (double)Rhino.Geometry.Intersect.Intersection.MeshRay(obstacles, ray); Point3d rayIntersection = ray.PointAt(rayEnd); Line ln = new Line(camPoint, rayIntersection); if (ln.IsValid & rayEnd > 0) { rayTree.Append(new GH_Line(ln), path); colorTree.Append(new GH_Colour(col), path); } } } } } sampler.Release(false); } bitmapUp.RotateFlip(RotateFlipType.Rotate180FlipNone); if (saveCubemaps) { gr.DrawImage(bitmapUp, imageWidth, 0); } bitmapUp.Dispose(); ///Get down view vp.SetCameraLocations(tarDown, camPoint); view.Redraw(); Bitmap bitmapDown = new Bitmap(view.CaptureToBitmap(size, viewMode)); if (saveCubemaps) { gr.DrawImage(bitmapDown, imageWidth, imageWidth * 2); } if (showRays) { GH_MemoryBitmap sampler = new GH_MemoryBitmap(bitmapDown); Color col = Color.Transparent; for (int x = 0; x < bitmapDown.Width; x++) { for (int y = 0; y < bitmapDown.Height; y++) { if (sampler.Sample(x, y, ref col)) { if (colors.Contains(col)) { GH_Path path = new GH_Path(i, colors.IndexOf(col)); Line line = vp.ClientToWorld(new System.Drawing.Point(x, y)); Ray3d ray = new Ray3d(vp.CameraLocation, -line.Direction); double rayEnd = (double)Rhino.Geometry.Intersect.Intersection.MeshRay(obstacles, ray); Point3d rayIntersection = ray.PointAt(rayEnd); Line ln = new Line(camPoint, rayIntersection); if (ln.IsValid & rayEnd > 0) { rayTree.Append(new GH_Line(ln), path); colorTree.Append(new GH_Colour(col), path); } } else if (!filterColors) { colors.Add(col); GH_Path path = new GH_Path(i, colors.IndexOf(col)); Line line = vp.ClientToWorld(new System.Drawing.Point(x, y)); Ray3d ray = new Ray3d(vp.CameraLocation, -line.Direction); double rayEnd = (double)Rhino.Geometry.Intersect.Intersection.MeshRay(obstacles, ray); Point3d rayIntersection = ray.PointAt(rayEnd); Line ln = new Line(camPoint, rayIntersection); if (ln.IsValid & rayEnd > 0) { rayTree.Append(new GH_Line(ln), path); colorTree.Append(new GH_Colour(col), path); } } } } } sampler.Release(false); } bitmapDown.Dispose(); } ///End pano directions loop if (saveCubemaps) { ///Save cubemap bitmap string s = i.ToString().PadLeft(pad, '0'); string saveText = folder + prefix + "_" + s + ".png"; cubemap.Save(saveText, System.Drawing.Imaging.ImageFormat.Png); cubemaps.Add(saveText); } cubemap.Dispose(); } } ///Restore initial camera setCamera(saveCam, Rhino.RhinoDoc.ActiveDoc.Views.ActiveView.ActiveViewport); Rhino.RhinoDoc.ActiveDoc.Views.ActiveView.Redraw(); DA.SetDataList(0, cubemaps); DA.SetDataTree(1, rayTree); DA.SetDataTree(2, colorTree); }
protected override void SolveInstance(IGH_DataAccess DA) { //Script to discretize a topography-mesh into cubes for the FFD solver // 2016-09-07 Christoph Waibel // //input: // x,y,z grid size // x,y,z cell numbers // origin point (all calculations use this as reference) // mesh geometry List <double> xyzsize = new List <double>(); if (!DA.GetDataList(0, xyzsize)) { return; } ; List <int> xyzcells = new List <int>(); if (!DA.GetDataList(1, xyzcells)) { return; } ; List <Mesh> meshs = new List <Mesh>(); if (!DA.GetDataList(2, meshs)) { return; } Point3d origin = Point3d.Unset; if (!DA.GetData(3, ref origin)) { return; } double tolerance = 0.01; //output: // list of cubes (as double [6]{xmin, xmax, ymin, ymax, zmin, zmax}) //1. create list of points on grid cells 0-point List <Point3d> pts = new List <Point3d>(); double xcelldist = xyzsize[0] / xyzcells[0]; double ycelldist = xyzsize[1] / xyzcells[1]; double zcelldist = xyzsize[2] / xyzcells[2]; for (int x = 0; x < xyzcells[0]; x++) { for (int y = 0; y < xyzcells[1]; y++) { pts.Add(new Point3d((x + 0.5) * xcelldist + origin[0], (y + 0.5) * ycelldist + origin[1], origin[2])); } } Vector3d vec = new Vector3d(0, 0, 1); //foreach grid cell List <Box> box = new List <Box>(); List <double[]> cubes = new List <double[]>(); foreach (Point3d pt in pts) { foreach (Mesh mesh in meshs) { //2. shoot rays straight up (from z-origin to zmax) //Ray3d ray = new Ray3d(new Point3d(pt[0] + 0.5 * (double)xcelldist, pt[1] + 0.5 * (double)ycelldist, pt[2]), vec); Ray3d ray = new Ray3d(new Point3d(pt[0], pt[1], pt[2]), vec); //3. check for intersections with mesh Point3d ptX1 = new Point3d(pt[0], pt[1], pt[2]); bool blninters = false; double inters1 = Rhino.Geometry.Intersect.Intersection.MeshRay(mesh, ray); if (inters1 > 0) { Point3d ptat1 = ray.PointAt(inters1); ray = new Ray3d(new Point3d(ptat1[0], ptat1[1], ptat1[2] + tolerance), vec); //flatten point to the next/previous grid step ptat1 = new Point3d(ptat1.X, ptat1.Y, Math.Round((ptat1[2] - origin[2]) / zcelldist, 0) * zcelldist + origin[2]); double inters2 = Rhino.Geometry.Intersect.Intersection.MeshRay(mesh, ray); if (inters2 > 0) { Point3d ptat2 = ray.PointAt(inters2); blninters = true; //repeat until there are no other intersections anymore while (blninters == true) { //5. create cube with xmin xmax ymin ymax zmin (all already known), and zmax (calculated with mesh intersection) // rounding the intersection-z-value to match the grid-z-values Point3d ptmax = new Point3d(ptat1[0] + 0.5 * xcelldist, ptat1[1] + 0.5 * ycelldist, Math.Round((ptat2[2] - origin[2]) / zcelldist, 0) * zcelldist + origin[2]); box.Add(new Box(new BoundingBox(new Point3d(ptat1[0] - 0.5 * xcelldist, ptat1 [1] - 0.5 * ycelldist, ptat1[2]), ptmax))); cubes.Add(new double[] { ptat1[0] - origin[0] - 0.5 * xcelldist, ptmax[0] - origin[0], ptat1[1] - origin[1] - 0.5 * ycelldist, ptmax[1] - origin[1], ptat1[2] - origin[2], ptmax[2] - origin[2] }); //check another intersection couple */------/* ptat1 = new Point3d(ptat2[0], ptat2[1], ptat2[2] + tolerance); ray = new Ray3d(ptat1, vec); inters1 = Rhino.Geometry.Intersect.Intersection.MeshRay(mesh, ray); if (inters1 > 0) { ptat1 = ray.PointAt(inters1); ray = new Ray3d(new Point3d(ptat1[0], ptat1[1], ptat1[2] + tolerance), vec); inters2 = Rhino.Geometry.Intersect.Intersection.MeshRay(mesh, ray); if (inters2 > 0) { ptat2 = ray.PointAt(inters2); } else { blninters = false; } } else { blninters = false; } } } } } } DA.SetDataList(0, box); DA.SetDataList(1, cubes); }
/// <summary> /// This is the method that actually does the work. /// </summary> /// <param name="DA">The DA object can be used to retrieve data from input parameters and /// to store data in output parameters.</param> protected override void SolveInstance(IGH_DataAccess DA) { ITargetLength TargetLength = null; bool reset = false; int Flip = 0; List <Curve> FC = new List <Curve>(); List <Point3d> FV = new List <Point3d>(); double FixT = 0.01; double PullStrength = 0.8; double SmoothStrength = 0.8; double LengthTol = 0.15; bool Minim = false; int Iters = 1; GH_ObjectWrapper Surf = new GH_ObjectWrapper(); DA.GetData <GH_ObjectWrapper>(0, ref Surf); GH_ObjectWrapper Obj = null; DA.GetData <GH_ObjectWrapper>(1, ref Obj); TargetLength = Obj.Value as ITargetLength; DA.GetDataList <Curve>(2, FC); DA.GetDataList <Point3d>(3, FV); DA.GetData <int>(4, ref Flip); DA.GetData <double>(5, ref PullStrength); DA.GetData <int>(6, ref Iters); DA.GetData <bool>(7, ref reset); if (PullStrength == 0) { Minim = true; } if (Surf.Value is GH_Mesh) { DA.GetData <Mesh>(0, ref M); M.Faces.ConvertQuadsToTriangles(); } else { double L = 1.0; MeshingParameters MeshParams = new MeshingParameters(); MeshParams.MaximumEdgeLength = 3 * L; MeshParams.MinimumEdgeLength = L; MeshParams.JaggedSeams = false; MeshParams.SimplePlanes = false; Brep SB = null; DA.GetData <Brep>(0, ref SB); Mesh[] BrepMeshes = Mesh.CreateFromBrep(SB, MeshParams); M = new Mesh(); foreach (var mesh in BrepMeshes) { M.Append(mesh); } } if (reset || initialized == false) { #region reset M.Faces.ConvertQuadsToTriangles(); P = M.ToPlanktonMesh(); initialized = true; AnchorV.Clear(); FeatureV.Clear(); FeatureE.Clear(); //Mark any vertices or edges lying on features for (int i = 0; i < P.Vertices.Count; i++) { Point3d Pt = P.Vertices[i].ToPoint3d(); AnchorV.Add(-1); for (int j = 0; j < FV.Count; j++) { if (Pt.DistanceTo(FV[j]) < FixT) { AnchorV[AnchorV.Count - 1] = j; } } FeatureV.Add(-1); for (int j = 0; j < FC.Count; j++) { double param = new double(); FC[j].ClosestPoint(Pt, out param); if (Pt.DistanceTo(FC[j].PointAt(param)) < FixT) { FeatureV[FeatureV.Count - 1] = j; } } } // int EdgeCount = P.Halfedges.Count / 2; for (int i = 0; i < EdgeCount; i++) { FeatureE.Add(-1); //同一条线分为两条线编号分别为2i和2i+1,朝向相对,两个的起始点为 int vStart = P.Halfedges[2 * i].StartVertex; int vEnd = P.Halfedges[2 * i + 1].StartVertex; Point3d PStart = P.Vertices[vStart].ToPoint3d(); Point3d PEnd = P.Vertices[vEnd].ToPoint3d(); for (int j = 0; j < FC.Count; j++) { double paramS = new double(); double paramE = new double(); Curve thisFC = FC[j]; thisFC.ClosestPoint(PStart, out paramS); thisFC.ClosestPoint(PEnd, out paramE); if ((PStart.DistanceTo(thisFC.PointAt(paramS)) < FixT) && (PEnd.DistanceTo(thisFC.PointAt(paramE)) < FixT)) { FeatureE[FeatureE.Count - 1] = j; } } } #endregion } else { for (int iter = 0; iter < Iters; iter++) { int EdgeCount = P.Halfedges.Count / 2; double[] EdgeLength = P.Halfedges.GetLengths(); List <bool> Visited = new List <bool>(); Vector3d[] Normals = new Vector3d[P.Vertices.Count]; for (int i = 0; i < P.Vertices.Count; i++) { Visited.Add(false); Normals[i] = Normal(P, i); } double t = LengthTol; //a tolerance for when to split/collapse edges double smooth = SmoothStrength; //smoothing strength double pull = PullStrength; //pull to target mesh strength // Split the edges that are too long for (int i = 0; i < EdgeCount; i++) { if (P.Halfedges[2 * i].IsUnused == false) { int vStart = P.Halfedges[2 * i].StartVertex; int vEnd = P.Halfedges[2 * i + 1].StartVertex; if ((Visited[vStart] == false) && (Visited[vEnd] == false)) { double L2 = TargetLength.Calculate(P, 2 * i); if (EdgeLength[2 * i] > (1 + t) * (4f / 3f) * L2) { int SplitHEdge = P.Halfedges.TriangleSplitEdge(2 * i); if (SplitHEdge != -1) { int SplitCenter = P.Halfedges[SplitHEdge].StartVertex; P.Vertices.SetVertex(SplitCenter, MidPt(P, i)); //update the feature information FeatureE.Add(FeatureE[i]); FeatureV.Add(FeatureE[i]); AnchorV.Add(-1); //2 additional new edges have also been created (or 1 if split was on a boundary) //mark these as non-features int CEdgeCount = P.Halfedges.Count / 2; while (FeatureE.Count < CEdgeCount) { FeatureE.Add(-1); } Visited.Add(true); int[] Neighbours = P.Vertices.GetVertexNeighbours(SplitCenter); foreach (int n in Neighbours) { Visited[n] = true; } } } } } } //Collapse the edges that are too short for (int i = 0; i < EdgeCount; i++) { if (P.Halfedges[2 * i].IsUnused == false) { int vStart = P.Halfedges[2 * i].StartVertex; int vEnd = P.Halfedges[2 * i + 1].StartVertex; if ((Visited[vStart] == false) && (Visited[vEnd] == false)) { if (!(AnchorV[vStart] != -1 && AnchorV[vEnd] != -1)) // if both ends are anchored, don't collapse { int Collapse_option = 0; //0 for none, 1 for collapse to midpt, 2 for towards start, 3 for towards end //if neither are anchorV if (AnchorV[vStart] == -1 && AnchorV[vEnd] == -1) { // if both on same feature (or neither on a feature) if (FeatureV[vStart] == FeatureV[vEnd]) { Collapse_option = 1; } // if start is on a feature and end isn't if ((FeatureV[vStart] != -1) && (FeatureV[vEnd] == -1)) { Collapse_option = 2; } // if end is on a feature and start isn't if ((FeatureV[vStart] == -1) && (FeatureV[vEnd] != -1)) { Collapse_option = 3; } } else // so one end must be an anchor { // if start is an anchor if (AnchorV[vStart] != -1) { // if both are on same feature, or if the end is not a feature if ((FeatureE[i] != -1) || (FeatureV[vEnd] == -1)) { Collapse_option = 2; } } // if end is an anchor if (AnchorV[vEnd] != -1) { // if both are on same feature, or if the start is not a feature if ((FeatureE[i] != -1) || (FeatureV[vStart] == -1)) { Collapse_option = 3; } } } Point3d Mid = MidPt(P, i); double L2 = TargetLength.Calculate(P, 2 * i); if ((Collapse_option != 0) && (EdgeLength[2 * i] < (1 - t) * 4f / 5f * L2)) { int Collapsed = -1; int CollapseRtn = -1; if (Collapse_option == 1) { Collapsed = P.Halfedges[2 * i].StartVertex; P.Vertices.SetVertex(Collapsed, MidPt(P, i)); CollapseRtn = P.Halfedges.CollapseEdge(2 * i); } if (Collapse_option == 2) { Collapsed = P.Halfedges[2 * i].StartVertex; CollapseRtn = P.Halfedges.CollapseEdge(2 * i); } if (Collapse_option == 3) { Collapsed = P.Halfedges[2 * i + 1].StartVertex; CollapseRtn = P.Halfedges.CollapseEdge(2 * i + 1); } if (CollapseRtn != -1) { int[] Neighbours = P.Vertices.GetVertexNeighbours(Collapsed); foreach (int n in Neighbours) { Visited[n] = true; } } } } } } } EdgeCount = P.Halfedges.Count / 2; if ((Flip == 0) && (PullStrength > 0)) { //Flip edges to reduce valence error for (int i = 0; i < EdgeCount; i++) { if (!P.Halfedges[2 * i].IsUnused && (P.Halfedges[2 * i].AdjacentFace != -1) && (P.Halfedges[2 * i + 1].AdjacentFace != -1) && (FeatureE[i] == -1) // don't flip feature edges ) { int Vert1 = P.Halfedges[2 * i].StartVertex; int Vert2 = P.Halfedges[2 * i + 1].StartVertex; int Vert3 = P.Halfedges[P.Halfedges[P.Halfedges[2 * i].NextHalfedge].NextHalfedge].StartVertex; int Vert4 = P.Halfedges[P.Halfedges[P.Halfedges[2 * i + 1].NextHalfedge].NextHalfedge].StartVertex; int Valence1 = P.Vertices.GetValence(Vert1); int Valence2 = P.Vertices.GetValence(Vert2); int Valence3 = P.Vertices.GetValence(Vert3); int Valence4 = P.Vertices.GetValence(Vert4); if (P.Vertices.NakedEdgeCount(Vert1) > 0) { Valence1 += 2; } if (P.Vertices.NakedEdgeCount(Vert2) > 0) { Valence2 += 2; } if (P.Vertices.NakedEdgeCount(Vert3) > 0) { Valence3 += 2; } if (P.Vertices.NakedEdgeCount(Vert4) > 0) { Valence4 += 2; } int CurrentError = Math.Abs(Valence1 - 6) + Math.Abs(Valence2 - 6) + Math.Abs(Valence3 - 6) + Math.Abs(Valence4 - 6); int FlippedError = Math.Abs(Valence1 - 7) + Math.Abs(Valence2 - 7) + Math.Abs(Valence3 - 5) + Math.Abs(Valence4 - 5); if (CurrentError > FlippedError) { P.Halfedges.FlipEdge(2 * i); } } } } else { //Flip edges based on angle for (int i = 0; i < EdgeCount; i++) { if (!P.Halfedges[2 * i].IsUnused && (P.Halfedges[2 * i].AdjacentFace != -1) && (P.Halfedges[2 * i + 1].AdjacentFace != -1) && (FeatureE[i] == -1) // don't flip feature edges ) { int Vert1 = P.Halfedges[2 * i].StartVertex; int Vert2 = P.Halfedges[2 * i + 1].StartVertex; int Vert3 = P.Halfedges[P.Halfedges[P.Halfedges[2 * i].NextHalfedge].NextHalfedge].StartVertex; int Vert4 = P.Halfedges[P.Halfedges[P.Halfedges[2 * i + 1].NextHalfedge].NextHalfedge].StartVertex; Point3d P1 = P.Vertices[Vert1].ToPoint3d(); Point3d P2 = P.Vertices[Vert2].ToPoint3d(); Point3d P3 = P.Vertices[Vert3].ToPoint3d(); Point3d P4 = P.Vertices[Vert4].ToPoint3d(); double A1 = Vector3d.VectorAngle(new Vector3d(P3 - P1), new Vector3d(P4 - P1)) + Vector3d.VectorAngle(new Vector3d(P4 - P2), new Vector3d(P3 - P2)); double A2 = Vector3d.VectorAngle(new Vector3d(P1 - P4), new Vector3d(P2 - P4)) + Vector3d.VectorAngle(new Vector3d(P2 - P3), new Vector3d(P1 - P3)); if (A2 > A1) { P.Halfedges.FlipEdge(2 * i); } } } } if (Minim) { Vector3d[] SmoothC = LaplacianSmooth(P, 1, smooth); for (int i = 0; i < P.Vertices.Count; i++) { if (AnchorV[i] == -1) // don't smooth feature vertices { P.Vertices.MoveVertex(i, 0.5 * SmoothC[i]); } } } Vector3d[] Smooth = LaplacianSmooth(P, 0, smooth); for (int i = 0; i < P.Vertices.Count; i++) { if (AnchorV[i] == -1) // don't smooth feature vertices { // make it tangential only Vector3d VNormal = Normal(P, i); double ProjLength = Smooth[i] * VNormal; Smooth[i] = Smooth[i] - (VNormal * ProjLength); P.Vertices.MoveVertex(i, Smooth[i]); if (P.Vertices.NakedEdgeCount(i) != 0)//special smoothing for feature edges { int[] Neighbours = P.Vertices.GetVertexNeighbours(i); int ncount = 0; Point3d Avg = new Point3d(); for (int j = 0; j < Neighbours.Length; j++) { if (P.Vertices.NakedEdgeCount(Neighbours[j]) != 0) { ncount++; Avg = Avg + P.Vertices[Neighbours[j]].ToPoint3d(); } } Avg = Avg * (1.0 / ncount); Vector3d move = Avg - P.Vertices[i].ToPoint3d(); move = move * smooth; P.Vertices.MoveVertex(i, move); } if (FeatureV[i] != -1)//special smoothing for feature edges { int[] Neighbours = P.Vertices.GetVertexNeighbours(i); int ncount = 0; Point3d Avg = new Point3d(); for (int j = 0; j < Neighbours.Length; j++) { if ((FeatureV[Neighbours[j]] == FeatureV[i]) || (AnchorV[Neighbours[j]] != -1)) { ncount++; Avg = Avg + P.Vertices[Neighbours[j]].ToPoint3d(); } } Avg = Avg * (1.0 / ncount); Vector3d move = Avg - P.Vertices[i].ToPoint3d(); move = move * smooth; P.Vertices.MoveVertex(i, move); } //projecting points onto the target along their normals if (pull > 0) { Point3d Point = P.Vertices[i].ToPoint3d(); Vector3d normal = Normal(P, i); Ray3d Ray1 = new Ray3d(Point, normal); Ray3d Ray2 = new Ray3d(Point, -normal); double RayPt1 = Rhino.Geometry.Intersect.Intersection.MeshRay(M, Ray1); double RayPt2 = Rhino.Geometry.Intersect.Intersection.MeshRay(M, Ray2); Point3d ProjectedPt; if ((RayPt1 < RayPt2) && (RayPt1 > 0) && (RayPt1 < 1.0)) { ProjectedPt = Point * (1 - pull) + pull * Ray1.PointAt(RayPt1); } else if ((RayPt2 < RayPt1) && (RayPt2 > 0) && (RayPt2 < 1.0)) { ProjectedPt = Point * (1 - pull) + pull * Ray2.PointAt(RayPt2); } else { ProjectedPt = Point * (1 - pull) + pull * M.ClosestPoint(Point); } P.Vertices.SetVertex(i, ProjectedPt); } if (FeatureV[i] != -1) //pull feature vertices onto feature curves { Point3d Point = P.Vertices[i].ToPoint3d(); Curve CF = FC[FeatureV[i]]; double param1 = 0.0; Point3d onFeature = new Point3d(); CF.ClosestPoint(Point, out param1); onFeature = CF.PointAt(param1); P.Vertices.SetVertex(i, onFeature); } } else { P.Vertices.SetVertex(i, FV[AnchorV[i]]); //pull anchor vertices onto their points } } //end new AnchorV = CompactByVertex(P, AnchorV); //compact the fixed points along with the vertices FeatureV = CompactByVertex(P, FeatureV); FeatureE = CompactByEdge(P, FeatureE); P.Compact(); //this cleans the mesh data structure of unused elements } } DA.SetData(0, P); }