/// <summary> /// Find regions of the input meshes that are horizontal, returns binned by Z-value. /// Currently only finds upward-facing regions. /// </summary> protected Dictionary <double, List <PlanarRegion> > FindPlanarZRegions(double minDimension, double dotNormalTol = 0.999) { Dictionary <double, List <PlanarRegion> > Regions = new Dictionary <double, List <PlanarRegion> >(); SpinLock region_lock = new SpinLock(); gParallel.ForEach(Meshes, (sliceMesh) => { if (sliceMesh.options.IsCavity == false) { return; } DMesh3 mesh = sliceMesh.mesh; HashSet <int> planar_tris = new HashSet <int>(); foreach (int tid in mesh.TriangleIndices()) { Vector3d n = mesh.GetTriNormal(tid); double dot = n.Dot(Vector3d.AxisZ); if (dot > dotNormalTol) { planar_tris.Add(tid); } } MeshConnectedComponents regions = new MeshConnectedComponents(mesh); regions.FilterF = planar_tris.Contains; regions.FindConnectedT(); foreach (var c in regions) { AxisAlignedBox3d bounds = MeshMeasurements.BoundsT(mesh, c.Indices); if (bounds.Width > minDimension && bounds.Height > minDimension) { double z = Math.Round(bounds.Center.z, PrecisionDigits); PlanarRegion planar = new PlanarRegion() { Mesh = mesh, Z = z, Triangles = c.Indices }; bool taken = false; region_lock.Enter(ref taken); List <PlanarRegion> zregions; if (Regions.TryGetValue(z, out zregions)) { zregions.Add(planar); } else { zregions = new List <PlanarRegion>() { planar }; Regions[z] = zregions; } region_lock.Exit(); } } }); return(Regions); }
public static void RecenterPivot(FScene scene, DMeshSO so, PivotLocation location, bool bInteractive) { if (so.Parent != scene) { DebugUtil.Log("OrientationChanges.RecenterPivot: tried to recenter pivot on non-scene-child"); return; } Frame3f sceneL = SceneTransforms.SceneToObject(so, Frame3f.Identity); AxisAlignedBox3d sceneBoundsL = AxisAlignedBox3d.Empty; so.SafeMeshRead((mesh) => { sceneBoundsL = MeshMeasurements.BoundsInFrame(mesh, sceneL); return(null); }); Vector3d originL = sceneBoundsL.Center; if (location == PivotLocation.BaseCenter) { originL -= sceneBoundsL.Extents.y * Vector3d.AxisY; } Frame3f newFrameL = new Frame3f(originL); RepositionPivotChangeOp change = new RepositionPivotChangeOp(newFrameL, so); scene.History.PushChange(change, false); if (bInteractive) { scene.History.PushInteractionCheckpoint(); } }
public static double GetVolume(MeshGeometry3D obj) { DMesh3 mesh = MeshGeometryToDMesh(obj); var triangles = mesh.TriangleIndices(); Func <int, Vector3d> getVertexF = (a) => { Vector3d V = mesh.GetVertex(a); return(V); }; Vector2d Vol = MeshMeasurements.VolumeArea(mesh, triangles, getVertexF); return(Vol.x / 1000); }
protected override void SolveInstance(IGH_DataAccess DA) { DMesh3_goo goo = null; DA.GetData(0, ref goo); DMesh3 msh = new DMesh3(goo.Value); var volArea = MeshMeasurements.VolumeArea(msh, msh.TriangleIndices(), msh.GetVertex); DA.SetData(0, volArea[1]); DA.SetData(1, volArea[0]); }
public static double GetOverlapVolume(MeshGeometry3D obj1, MeshGeometry3D obj2) { DMesh3 mesh1 = MeshGeometryToDMesh(obj1); DMesh3 mesh2 = MeshGeometryToDMesh(obj2); DMesh3 MI = BooleanIntersection(mesh1, mesh2); var triangles = MI.TriangleIndices(); Func <int, Vector3d> getVertexF = (a) => { Vector3d V = MI.GetVertex(a); return(V); }; Vector2d Vol = MeshMeasurements.VolumeArea(MI, triangles, getVertexF); return(Vol.x / 1000); }
public void EndStroke() { if (CurrentStroke.Count >= 2) { DMesh3 mesh = Target.Mesh; TransformSequence toScene = SceneTransforms.ObjectToSceneXForm(Target); List <int> tris1 = new List <int>(), tris2 = new List <int>(); Ray3f first = CurrentStroke[0], last = CurrentStroke[CurrentStroke.Count - 1]; Vector3f v0 = PlaneFrameS.RayPlaneIntersection(first.Origin, first.Direction, 2); Vector3f v1 = PlaneFrameS.RayPlaneIntersection(last.Origin, last.Direction, 2); Vector3f planeN = Vector3f.Cross(first.Direction, last.Direction); Frame3f planeF = new Frame3f((v0 + v1) / 2, planeN); foreach (int tid in mesh.TriangleIndices()) { Vector3f c = (Vector3f)mesh.GetTriCentroid(tid); c = toScene.TransformP(c); if (planeF.DistanceToPlaneSigned(c, 2) < 0) { tris1.Add(tid); } else { tris2.Add(tid); } } double area1 = MeshMeasurements.AreaT(mesh, tris1); double area2 = MeshMeasurements.AreaT(mesh, tris2); lastSelection = new MeshFaceSelection(mesh); lastSelection.Select((area1 > area2) ? tris2 : tris1); lastSelection.LocalOptimize(); if (OnStrokeCompletedF != null) { OnStrokeCompletedF(Target, lastSelection); } } CurrentStroke.Clear(); }
public static List <double> Volumes(MeshGeometry3D mesh) { DMesh3 m3 = MeshGeometryToDMesh(mesh); DMesh3[] mC = MeshConnectedComponents.Separate(m3); List <double> ListVol = new List <double>(); foreach (DMesh3 m in mC) { var triangles = m.TriangleIndices(); Func <int, Vector3d> getVertexF = (a) => { Vector3d V = m.GetVertex(a); return(V); }; Vector2d Vol = MeshMeasurements.VolumeArea(m, triangles, getVertexF); ListVol.Add(Vol.x / 1000); } return(ListVol); }
/// <summary> /// when the socket is updated, shift the ground plane to be directly below it /// </summary> public static void AddRepositionGroundPlaneOnSocketEdit() { OG.OnSocketUpdated += () => { // compute scene-space bbox of socket mesh Frame3f socketF = OG.Socket.Socket.GetLocalFrame(CoordSpace.ObjectCoords); AxisAlignedBox3d boundsS = MeshMeasurements.Bounds(OG.Socket.Socket.Mesh, socketF.FromFrameP); // vertically translate bounds objects to be at same y // (assumes they are xz planes!!) Vector3d baseS = boundsS.Center - boundsS.Extents[1] * Vector3d.AxisY; Vector3d baseW = OG.Scene.ToWorldP(baseS); foreach (var go in OG.Scene.BoundsObjects) { Vector3f pos = go.GetPosition(); pos.y = (float)baseW.y; go.SetPosition(pos); } }; }
public virtual void Update() { if (MeshSource == null) { throw new Exception("LegSqueezeOp: must set valid MeshSource to compute!"); } IMesh mesh = MeshSource.GetIMesh(); if (mesh.HasVertexNormals == false) { throw new Exception("LegSqueezeOp: input mesh does not have surface normals..."); } Displacement.Resize(mesh.MaxVertexID); // compute extents along axis double upper_t = UpperPoint.Dot(Axis); Interval1d axis_extents = MeshMeasurements.ExtentsOnAxis(mesh, axis); double lower_t = axis_extents.a; // compute approximate skeleton int nVertices = midPoints.Count + 2; Vector3d[] centers = new Vector3d[nVertices]; int[] counts = new int[nVertices]; foreach (int vid in mesh.VertexIndices()) { Vector3d v = mesh.GetVertex(vid); double t = v.Dot(ref axis); int iBin = 0; if (t > upper_t) { iBin = nVertices - 1; } else if (t > lower_t) { double unit_t = (t - lower_t) / (upper_t - lower_t); iBin = 1; for (int k = 0; k < midPoints.Count; ++k) { if (unit_t > midPoints[k].x) { iBin++; } } } // else iBin = 0, as initialized centers[iBin] += v; counts[iBin]++; } for (int k = 0; k < centers.Length; ++k) { centers[k] /= counts[k]; } // todo: can do this in parallel foreach (int vid in mesh.VertexIndices()) { Vector3d v = mesh.GetVertex(vid); double t = v.Dot(axis); if (t > upper_t) { continue; } Vector3d center = centers[0]; double percent = 0; if (t >= upper_t) { percent = reduce_percent_top; center = centers[nVertices - 1]; } else if (t <= lower_t) { percent = reduce_percent_bottom; center = centers[0]; } else if (midPoints.Count == 0) { double unit_t = (t - lower_t) / (upper_t - lower_t); unit_t = MathUtil.WyvillRise01(unit_t); percent = MathUtil.Lerp(reduce_percent_bottom, reduce_percent_top, unit_t); } else { double unit_t = (t - lower_t) / (upper_t - lower_t); double low_percent = reduce_percent_bottom; double high_percent = reduce_percent_top; Vector3d low_center = centers[0]; Vector3d high_center = centers[0]; double low_t = 0.0, high_t = 0; for (int i = 0; i < midPoints.Count; ++i) { if (unit_t < midPoints[i].x) { high_t = midPoints[i].x; high_percent = midPoints[i].y; high_center = centers[i + 1]; break; } low_t = midPoints[i].x; low_percent = midPoints[i].y; low_center = centers[i + 1]; } if (high_t == 0) { high_t = 1.0; high_percent = reduce_percent_top; high_center = centers[nVertices - 1]; } double a = (unit_t - low_t) / (high_t - low_t); a = MathUtil.WyvillRise01(a); percent = MathUtil.Lerp(low_percent, high_percent, a); center = Vector3d.Lerp(low_center, high_center, a); } percent = percent / 100; double scale = 1.0 - percent; Vector3d v_scaled = (v - center) * new Vector3d(scale, 1, scale) + center; Displacement[vid] = v_scaled - v; } result_valid = true; }
/// <summary> /// This is the action we give to the trim-scan tool, to run on accept /// </summary> public static void CropScanFromSelection(DMeshSO so, MeshFaceSelection selection, object tool) { DMesh3 beforeMesh = new DMesh3(so.Mesh); DMesh3 mesh = so.Mesh; // [RMS] if we are using the two-point tool, then we can use the user input points to // try to figure out an up axis, by assuming the first point is on the base of the scan. Steps are: // 1) guess a midpoint. Currently centroid of upper-half of geodesic selection. // 2) construct up axis as (midpoint-basepoint). this axis to Y-up. Vector3f upAxisS = Vector3f.AxisY; TwoPointFaceSelectionTool ptool = tool as TwoPointFaceSelectionTool; if (ptool != null) { var cache = ptool.SelectionCache; Interval1d range = new Interval1d(cache.CurrentScalarThreshold / 2, cache.CurrentScalarThreshold); List <int> triangles = new List <int>(selection.Count); cache.FindTrianglesInScalarInterval(range, triangles); Vector3d c = MeshMeasurements.Centroid(triangles, mesh.GetTriCentroid); Vector3d cS = SceneTransforms.ObjectToSceneP(so, c); Vector3d basePosS = ptool.SourcePositionS.Origin; upAxisS = (Vector3f)(cS - basePosS).Normalized; } // crop scan and fill top hole List <int> borderTris = selection.FindBorderTris(); MeshEditor editor = new MeshEditor(mesh); editor.RemoveTriangles((tid) => { return(selection.IsSelected(tid) == false); }, true); if (OGActions.FillHoleInScan) { SmoothedHoleFill fill = new SmoothedHoleFill(mesh) { TargetEdgeLength = 2.5f, SmoothAlpha = 0.5f, BorderHintTris = borderTris, OffsetDirection = SceneTransforms.SceneToObjectN(so, upAxisS), OffsetDistance = (ptool != null) ? 25.0 : 0.0 }; fill.Apply(); } so.NotifyMeshEdited(); DMesh3 afterMesh = new DMesh3(so.Mesh); so.GetScene().History.PushChange(new ReplaceEntireMeshChange(so, beforeMesh, afterMesh), true); mesh = so.Mesh; // Now we auto-align the scan so it points upwards, and then // recenter pivot and shift to above ground plane if (ptool != null) { Vector3d basePosS = ptool.SourcePositionS.Origin; Quaternionf alignUp = Quaternionf.FromTo(upAxisS, Vector3f.AxisY); // rotate part so that axis points up Frame3f curF = so.GetLocalFrame(CoordSpace.SceneCoords); Frame3f newF = curF.Rotated(alignUp); TransformSOChange alignUpChange = new TransformSOChange(so, curF, newF, CoordSpace.SceneCoords); basePosS = newF.FromFrameP(curF.ToFrameP(basePosS)); // map to new frame so.GetScene().History.PushChange(alignUpChange, false); // recenter pivot at bbox center // [RMS] previously was using vertex centroid, but this is then affected by mesh density // (maybe tri centroid? but bbox makes more sense...and below we assume box center) Vector3d centerL = mesh.CachedBounds.Center; Vector3d centerO = newF.FromFrameP(centerL); Frame3f newPivotO = new Frame3f(centerO); so.GetScene().History.PushChange(new RepositionPivotChangeOp(newPivotO, so), false); // position above ground plane AxisAlignedBox3d bounds = so.Mesh.CachedBounds; float h = (float)bounds.Height; Vector3f o = newPivotO.Origin; Vector3f translateO = new Vector3f(-o.x, h * 0.5f - o.y + BaseHeightAboveGroundPlaneMM, -o.z); //Vector3f translateO = new Vector3f(0, h * 0.5f - o.y + BaseHeightAboveGroundPlaneMM, 0); newPivotO.Translate(translateO); so.GetScene().History.PushChange(new TransformSOChange(so, newPivotO, CoordSpace.ObjectCoords), false); // save base point in frame of scan basePosS += translateO; Vector3d basePosL = SceneTransforms.SceneToObjectP(so, basePosS); OG.Scan.UserBasePoint = basePosL; } so.GetScene().History.PushInteractionCheckpoint(); }