public static void test_levelset_basic() { //DMesh3 mesh = TestUtil.MakeCappedCylinder(false); //MeshTransforms.Scale(mesh, 1, 3, 1); DMesh3 mesh = TestUtil.LoadTestMesh(Program.TEST_FILES_PATH + "bunny_open_base.obj"); AxisAlignedBox3d bounds = mesh.CachedBounds; float cellSize = (float)bounds.MaxDim / 32.0f; MeshSignedDistanceGrid levelSet = new MeshSignedDistanceGrid(mesh, cellSize); levelSet.Compute(); Vector3i dims = levelSet.Dimensions; int midx = dims.x / 2; int midy = dims.y / 2; int midz = dims.z / 2; //for ( int xi = 0; xi < dims.x; ++xi ) { // System.Console.Write(levelSet[xi, yi, zi] + " "); //} for (int yi = 0; yi < dims.y; ++yi) { System.Console.Write(levelSet[midx, yi, midz] + " "); } System.Console.WriteLine(); DMesh3 tmp = new DMesh3(); MeshEditor editor = new MeshEditor(tmp); for (int x = 0; x < dims.x; ++x) { for (int y = 0; y < dims.y; ++y) { for (int z = 0; z < dims.z; ++z) { if (levelSet[x, y, z] < 0) { Vector3f c = levelSet.CellCenter(x, y, z); editor.AppendBox(new Frame3f(c), cellSize); } } } } TestUtil.WriteTestOutputMesh(tmp, "LevelSetInterior.obj"); TestUtil.WriteTestOutputMesh(mesh, "LevelSetInterior_src.obj"); }
virtual public void PreRender() { if (in_shutdown()) { return; } if (scale_needs_update) { currentDims = originalDims; currentDims.Scale(scale_x, scale_y, scale_z); Vector3f s = new Vector3f((float)scale_x, (float)scale_y, (float)scale_z); if (use_object_frame) { foreach (var obj in objects) { apply_object_scale(obj, s); } } else { foreach (var obj in objects) { apply_scene_scale(obj, s); } } //if (objects.Count == 1) { // objects[0].curLocalScale = s * objects[0].localScale; // Scene.History.PushChange( // new TransformSOChange(objects[0].SO, objects[0].curLocalScale), false); //} else { // foreach (var obj in objects) { // Frame3f f = obj.sceneFrame; // f.Origin = s * (f.Origin - sharedOriginS) + sharedOriginS; // obj.curSceneFrame = f; // obj.curLocalScale = s * obj.localScale; // Scene.History.PushChange( // new TransformSOChange(obj.SO, obj.curSceneFrame, CoordSpace.SceneCoords, obj.curLocalScale), false); // } //} scale_needs_update = false; } }
public PlaneIntersectionTraversal(DMesh3 mesh, double z) { this.Mesh = mesh; this.Z = z; this.NextBoxF = (box, depth) => { return(Z >= box.Min.z && Z <= box.Max.z); }; this.NextTriangleF = (tID) => { AxisAlignedBox3d box = Mesh.GetTriBounds(tID); if (Z >= box.Min.z && z <= box.Max.z) { triangles.Add(tID); } }; }
public override void postprocess_target_objects() { AxisAlignedBox3d bounds = SceneMeshes[0].CachedBounds; for (int k = 1; k < InputSOs.Count; ++k) { bounds.Contain(SceneMeshes[k].CachedBounds); } MaxDimension = bounds.MaxDim; double cell_size = ToolDefaults.DefaultVoxelSceneSizeF(new AxisAlignedBox3d(MaxDimension, MaxDimension, MaxDimension));; set_grid_cell_size(cell_size); set_mesh_cell_size(cell_size); set_blend_distance(5 * cell_size); set_min_comp_size(2.0); }
protected override Result RunCommand(RhinoDoc doc, RunMode mode) { DMesh3 mesh = new DMesh3(MakeRemeshedCappedCylinder(1.0), true); AxisAlignedBox3d bounds = mesh.GetBounds(); List <IMesh> result_meshes = new List <IMesh>(); LaplacianMeshDeformer deformer = new LaplacianMeshDeformer(mesh); // constrain bottom points foreach (int vid in mesh.VertexIndices()) { g3.Vector3d v = mesh.GetVertex(vid); bool bottom = (v.y - bounds.Min.y) < 0.01f; if (bottom) { deformer.SetConstraint(vid, v, 10); } } // constrain one other vtx int ti = MeshQueries.FindNearestTriangle_LinearSearch(mesh, new g3.Vector3d(2, 5, 2)); int v_pin = mesh.GetTriangle(ti).a; g3.Vector3d cons_pos = mesh.GetVertex(v_pin); cons_pos += new g3.Vector3d(0.5, 0.5, 0.5); deformer.SetConstraint(v_pin, cons_pos, 10); deformer.Initialize(); g3.Vector3d[] resultV = new g3.Vector3d[mesh.MaxVertexID]; deformer.Solve(resultV); foreach (int vid in mesh.VertexIndices()) { mesh.SetVertex(vid, resultV[vid]); } var rhinoMesh = GopherUtil.ConvertToRhinoMesh(mesh); doc.Objects.AddMesh(rhinoMesh); return(Result.Success); }
// [RMS] this only tests some basic cases... public static void test_LaplacianDeformation() { // compact version DMesh3 mesh = new DMesh3(TestUtil.MakeRemeshedCappedCylinder(1.0), true); Debug.Assert(mesh.IsCompact); AxisAlignedBox3d bounds = mesh.GetBounds(); List <IMesh> result_meshes = new List <IMesh>(); LaplacianMeshDeformer deformer = new LaplacianMeshDeformer(mesh); // constrain bottom points foreach (int vid in mesh.VertexIndices()) { Vector3d v = mesh.GetVertex(vid); bool bottom = (v.y - bounds.Min.y) < 0.01f; if (bottom) { deformer.SetConstraint(vid, v, 10); } } // constrain one other vtx int ti = MeshQueries.FindNearestTriangle_LinearSearch(mesh, new Vector3d(2, 5, 2)); int v_pin = mesh.GetTriangle(ti).a; Vector3d cons_pos = mesh.GetVertex(v_pin); cons_pos += new Vector3d(0.5, 0.5, 0.5); deformer.SetConstraint(v_pin, cons_pos, 10); result_meshes.Add(TestUtil.MakeMarker(mesh.GetVertex(v_pin), 0.2f, Colorf.Red)); deformer.Initialize(); Vector3d[] resultV = new Vector3d[mesh.MaxVertexID]; deformer.Solve(resultV); foreach (int vid in mesh.VertexIndices()) { mesh.SetVertex(vid, resultV[vid]); } result_meshes.Add(mesh); TestUtil.WriteDebugMeshes(result_meshes, "___LAPLACIAN_result.obj"); }
override public bool FindRayIntersection(Ray3f worldRay, out SORayHit hit) { hit = null; // project world ray into local coords FScene scene = GetScene(); Ray3f sceneRay = scene.ToSceneRay(worldRay); Ray3f localRay = SceneTransforms.SceneToObject(this, sceneRay); // also need width in local coords float sceneWidth = scene.ToSceneDimension(visibleWidth); float localWidth = SceneTransforms.SceneToObject(this, sceneWidth) * HitWidthMultiplier; // bounding-box hit test (would be nice to do w/o object allocation...) AxisAlignedBox3d hitBox = localBounds; hitBox.Expand(localWidth); IntrRay3AxisAlignedBox3 box_test = new IntrRay3AxisAlignedBox3(localRay, hitBox); if (box_test.Find() == false) { return(false); } // raycast against curve (todo: spatial data structure for this? like 2D polycurve bbox tree?) double rayHitT; if (CurveUtils.FindClosestRayIntersection(curve, localWidth, localRay, out rayHitT)) { hit = new SORayHit(); // transform local hit point back into world coords Vector3f rayPos = localRay.PointAt((float)rayHitT); Vector3f scenePos = SceneTransforms.ObjectToSceneP(this, rayPos); hit.hitPos = SceneTransforms.SceneToWorldP(scene, scenePos); hit.fHitDist = worldRay.Project(hit.hitPos); hit.hitNormal = Vector3f.Zero; hit.hitGO = root; hit.hitSO = this; return(true); } return(false); }
static public bool DoClipping(ref double t0, ref double t1, Vector3D origin, Vector3D direction, AxisAlignedBox3d box, bool solid, ref int quantity, ref Vector3D point0, ref Vector3D point1, ref IntersectionType intrType) { Vector3D BOrigin = origin - box.Center; Vector3D extent = box.Extents; double saveT0 = t0, saveT1 = t1; bool notAllClipped = Clip(+direction.x, -BOrigin.x - extent.x, ref t0, ref t1) && Clip(-direction.x, +BOrigin.x - extent.x, ref t0, ref t1) && Clip(+direction.y, -BOrigin.y - extent.y, ref t0, ref t1) && Clip(-direction.y, +BOrigin.y - extent.y, ref t0, ref t1) && Clip(+direction.z, -BOrigin.z - extent.z, ref t0, ref t1) && Clip(-direction.z, +BOrigin.z - extent.z, ref t0, ref t1); if (notAllClipped && (solid || t0 != saveT0 || t1 != saveT1)) { if (t1 > t0) { intrType = IntersectionType.Segment; quantity = 2; point0 = origin + t0 * direction; point1 = origin + t1 * direction; } else { intrType = IntersectionType.Point; quantity = 1; point0 = origin + t0 * direction; } } else { quantity = 0; intrType = IntersectionType.Empty; } return(intrType != IntersectionType.Empty); }
public virtual void Update() { base.begin_update(); int start_timestamp = this.CurrentInputTimestamp; if (mesh_sources == null) { throw new Exception("MeshVoxelBooleanOp: must set valid MeshSource to compute!"); } try { ResultMesh = null; if (source_edge_stats == null) { source_edge_stats = new List <Vector3d>(); source_bounds = AxisAlignedBox3d.Empty; foreach (DMeshSourceOp op in mesh_sources) { Vector3d einfo = new Vector3d(); MeshQueries.EdgeLengthStats(op.GetDMeshUnsafe(), out einfo.x, out einfo.y, out einfo.z); source_edge_stats.Add(einfo); source_bounds.Contain(op.GetDMeshUnsafe().CachedBounds); } } //ResultMesh = compute_blend(); //ResultMesh = compute_blend_bounded(); ResultMesh = compute_blend_analytic(); if (ResultMesh.TriangleCount == 0) { ResultMesh = base.make_failure_output(null); } base.complete_update(); } catch (Exception e) { PostOnOperatorException(e); ResultMesh = base.make_failure_output(mesh_sources[0].GetDMeshUnsafe()); base.complete_update(); } }
/// <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); } }; }
/// <summary> /// initialize points w/ known base point and up direction /// </summary> public void Initialize_KnownBasePoint(Vector3d basePointL, Vector3f upAxis) { DMeshSO TargetMeshSO = TargetSO as DMeshSO; // initialize w/ auto-fit box DMesh3 mesh = TargetMeshSO.Mesh; DMeshAABBTree3 spatial = TargetMeshSO.Spatial; meshBounds = mesh.CachedBounds; create_preview_so(); /*Frame3f frameO = TargetSO.GetLocalFrame(CoordSpace.ObjectCoords);*/ // reproject base point onto surface in case somehow it is wrong Vector3f basePointUpdatedL = MeshQueries.NearestPointFrame(mesh, spatial, basePointL).Origin; Vector3f BasePointS = SceneTransforms.ObjectToSceneP(TargetSO, basePointUpdatedL); Vector3f upAxisL = Vector3f.AxisY; Vector3f topPointL = basePointUpdatedL + upAxisL * (float)meshBounds.Height; topPointL = MeshQueries.NearestPointFrame(mesh, spatial, topPointL).Origin; Vector3f TopPointS = SceneTransforms.ObjectToSceneP(TargetSO, topPointL); // shoot ray forward in scene, to find front point Vector3f forwardL = SceneTransforms.SceneToObjectN(TargetSO, -Vector3f.AxisZ); Frame3f fwHitFrameL; bool bHit = MeshQueries.RayHitPointFrame(mesh, spatial, new Ray3d(meshBounds.Center, forwardL), out fwHitFrameL); if (!bHit) { throw new Exception("SocketAlignmentTool.Initialize_KnownBasePoint: ray missed!"); } Vector3f FrontPointS = SceneTransforms.ObjectToSceneP(TargetSO, fwHitFrameL.Origin); SetPointPosition(BasePointID, new Frame3f(BasePointS), CoordSpace.SceneCoords); SetPointPosition(FrontPointID, new Frame3f(FrontPointS), CoordSpace.SceneCoords); SetPointPosition(TopPointID, new Frame3f(TopPointS), CoordSpace.SceneCoords); }
override public void Apply() { float VerticalSpaceFudge = 10.0f; DMeshSO TargetMeshSO = TargetSO as DMeshSO; Frame3f curFrameS = TargetSO.GetLocalFrame(CoordSpace.SceneCoords); TransformSOChange change = new TransformSOChange(TargetSO, curFrameS, lastPreviewFrameS, CoordSpace.SceneCoords); Scene.History.PushChange(change, false); Frame3f newFrameS = new Frame3f(SceneTransforms.ObjectToSceneP(TargetSO, meshBounds.Center)); RepositionPivotChangeOp pivot1 = new RepositionPivotChangeOp(newFrameS, TargetMeshSO); Scene.History.PushChange(pivot1, false); newFrameS = TargetSO.GetLocalFrame(CoordSpace.SceneCoords); AxisAlignedBox3d bounds = TargetMeshSO.Mesh.CachedBounds; float h = (float)bounds.Height; Vector3f o = newFrameS.Origin; Vector3f translate = new Vector3f(-o.x, h * 0.5f - o.y + VerticalSpaceFudge, -o.z); Frame3f centeredFrameS = newFrameS.Translated(translate); TransformSOChange centerChange = new TransformSOChange(TargetSO, newFrameS, centeredFrameS, CoordSpace.SceneCoords); Scene.History.PushChange(centerChange, false); newFrameS = TargetSO.GetLocalFrame(CoordSpace.SceneCoords); o = newFrameS.Origin; o.y = 0; newFrameS.Origin = o; RepositionPivotChangeOp pivot2 = new RepositionPivotChangeOp(newFrameS, TargetMeshSO); Scene.History.PushChange(pivot2, false); Scene.History.PushInteractionCheckpoint(); }
public static AxisAlignedBox3d Bounds(IMesh mesh, Func <Vector3D, Vector3D> TransformF) { AxisAlignedBox3d bounds = AxisAlignedBox3d.Empty; if (TransformF == null) { foreach (int vID in mesh.VertexIndices()) { bounds.Contain(mesh.GetVertex(vID)); } } else { foreach (int vID in mesh.VertexIndices()) { Vector3D vT = TransformF(mesh.GetVertex(vID)); bounds.Contain(vT); } } return(bounds); }
public static AxisAlignedBox3d Bounds(NGonsCore.geometry3Sharp.mesh.DMesh3 mesh, Func <Vector3D, Vector3D> TransformF) { AxisAlignedBox3d bounds = AxisAlignedBox3d.Empty; if (TransformF == null) { foreach (Vector3D v in mesh.Vertices()) { bounds.Contain(v); } } else { foreach (Vector3D v in mesh.Vertices()) { Vector3D vT = TransformF(v); bounds.Contain(vT); } } return(bounds); }
public static void MoveToPrintBed(FScene scene, DMeshSO so, bool bInteractive) { TransformSequence seq = SceneTransforms.ObjectToSceneXForm(so); AxisAlignedBox3d bounds = BoundsUtil.Bounds(so.Mesh.Vertices(), seq); Frame3f curFrameS = so.GetLocalFrame(CoordSpace.SceneCoords); float dy = (float)(bounds.Center.y - bounds.Extents.y); if (Math.Abs(dy) > MathUtil.ZeroTolerancef) { Frame3f newFrameS = curFrameS; newFrameS.Origin = curFrameS.Origin - dy * Vector3f.AxisY; TransformSOChange change = new TransformSOChange(so, curFrameS, newFrameS, CoordSpace.SceneCoords); change.Tags.Add("MoveToPrintBed"); scene.History.PushChange(change, false); if (bInteractive) { scene.History.PushInteractionCheckpoint(); } } }
public void InitializeOnTarget(DMeshSO target, double initial_width) { AxisAlignedBox3d bounds = target.Mesh.CachedBounds; Vector3d c = bounds.Center; SORayHit nearestPt; target.FindNearest(c, double.MaxValue, out nearestPt, CoordSpace.ObjectCoords); c = nearestPt.hitPos; Vector3d up = c + initial_width * Vector3d.AxisY; target.FindNearest(up, double.MaxValue, out nearestPt, CoordSpace.ObjectCoords); up = nearestPt.hitPos; Vector3d down = c - initial_width * Vector3d.AxisY; target.FindNearest(down, double.MaxValue, out nearestPt, CoordSpace.ObjectCoords); down = nearestPt.hitPos; SetPointPosition_Internal(StartPointID, new Frame3f(up), CoordSpace.ObjectCoords); SetPointPosition_Internal(EndPointID, new Frame3f(down), CoordSpace.ObjectCoords); }
protected override void SolveInstance(IGH_DataAccess DA) { int num_cells = 128; DMesh3_goo dMsh_goo = null; DA.GetData(0, ref dMsh_goo); DA.GetData(1, ref num_cells); DMesh3 dMsh_copy = new DMesh3(dMsh_goo.Value); double cell_size = dMsh_copy.CachedBounds.MaxDim / num_cells; DMeshAABBTree3 spatial = new DMeshAABBTree3(dMsh_copy, autoBuild: true); AxisAlignedBox3d bounds = dMsh_copy.CachedBounds; double cellsize = bounds.MaxDim / num_cells; ShiftGridIndexer3 indexer = new ShiftGridIndexer3(bounds.Min, cellsize); Bitmap3 bmp = new Bitmap3(new Vector3i(num_cells, num_cells, num_cells)); foreach (Vector3i idx in bmp.Indices()) { g3.Vector3d v = indexer.FromGrid(idx); bmp.Set(idx, spatial.IsInside(v)); } VoxelSurfaceGenerator voxGen = new VoxelSurfaceGenerator(); voxGen.Voxels = bmp; voxGen.Generate(); DMesh3 voxMesh = voxGen.Meshes[0]; var vecSize = dMsh_copy.CachedBounds.Extents; var box = dMsh_copy.GetBounds(); // Scale voxel mesh //MeshTransforms.Scale(voxMesh,) DA.SetData(0, voxMesh); }
public void Compute() { // figure out origin & dimensions AxisAlignedBox3d bounds = Mesh.CachedBounds; float fBufferWidth = 2 * BufferCells * (float)CellSize; grid_origin = (Vector3f)bounds.Min - fBufferWidth * Vector3f.One; Vector3f max = (Vector3f)bounds.Max + fBufferWidth * Vector3f.One; int ni = (int)((max.x - grid_origin.x) / (float)CellSize) + 1; int nj = (int)((max.y - grid_origin.y) / (float)CellSize) + 1; int nk = (int)((max.z - grid_origin.z) / (float)CellSize) + 1; scalar_grid = new DenseGrid3f(); if (ComputeMode == ComputeModes.FullGrid) { make_grid_dense(grid_origin, (float)CellSize, ni, nj, nk, scalar_grid); } else { make_grid(grid_origin, (float)CellSize, ni, nj, nk, scalar_grid); } }
public static void FitCurrentSelectionToView() { AxisAlignedBox3d fitBox = AxisAlignedBox3d.Zero; if (CC.ActiveScene.Selected.Count == 0) { fitBox = CC.Objects.GetPrintMeshesBounds(false); } else { fitBox = AxisAlignedBox3d.Empty; foreach (var so in CC.ActiveScene.Selected) { fitBox.Contain(so.GetBoundingBox(CoordSpace.SceneCoords).ToAABB()); } } double height = 3 * fitBox.Height; if (height < 10.0f) { height = 10.0f; } double width = 1.5 * Math.Sqrt(fitBox.Width * fitBox.Width + fitBox.Depth * fitBox.Depth); Vector3d center = fitBox.Center; if (width > height) { CC.ActiveScene.ActiveCamera.Animator().AnimateFitWidthToView((Vector3f)center, (float)width, CoordSpace.SceneCoords, 0.5f); } else { CC.ActiveScene.ActiveCamera.Animator().AnimateFitHeightToView((Vector3f)center, (float)height, CoordSpace.SceneCoords, 0.5f); } UpdateViewClippingBounds(); }
public static void CalculateUVs(this DMesh3 dMesh) { dMesh.EnableVertexUVs(Vector2f.Zero); OrthogonalPlaneFit3 orth = new OrthogonalPlaneFit3(dMesh.Vertices()); Frame3f frame = new Frame3f(orth.Origin, orth.Normal); AxisAlignedBox3d bounds = dMesh.CachedBounds; AxisAlignedBox2d boundsInFrame = new AxisAlignedBox2d(); for (int i = 0; i < 8; i++) { boundsInFrame.Contain(frame.ToPlaneUV((Vector3f)bounds.Corner(i), 3)); } Vector2f min = (Vector2f)boundsInFrame.Min; float width = (float)boundsInFrame.Width; float height = (float)boundsInFrame.Height; for (int i = 0; i < dMesh.VertexCount; i++) { Vector2f UV = frame.ToPlaneUV((Vector3f)dMesh.GetVertex(i), 3); UV.x = (UV.x - min.x) / width; UV.y = (UV.y - min.y) / height; dMesh.SetVertexUV(i, UV); } }
override public bool FindRayIntersection(Ray3f ray, out SORayHit hit) { hit = null; Ray sceneRay = GetScene().ToSceneRay(ray); Frame3f frameL = GetLocalFrame(CoordSpace.ObjectCoords); Ray localRay = frameL.ToFrame(sceneRay); float sceneWidth = GetScene().ToSceneDimension(visibleWidth); AxisAlignedBox3d hitBox = localBounds; hitBox.Expand(sceneWidth * 0.5f); Bounds hitBounds = new Bounds((Vector3)hitBox.Center, (Vector3)hitBox.Diagonal); if (hitBounds.IntersectRay(localRay) == false) { return(false); } double rayHitT; //if (CurveUtils.FindClosestRayIntersection(curve, sceneWidth * 0.5f, localRay, out rayHitT)) { if (CurveUtils.FindClosestRayIntersection(curve, sceneWidth, localRay, out rayHitT)) { hit = new SORayHit(); hit.fHitDist = (float)rayHitT; hit.hitPos = localRay.GetPoint(hit.fHitDist); hit.hitPos = GetScene().ToWorldP(frameL.FromFrameP(hit.hitPos)); hit.hitNormal = Vector3.zero; hit.hitGO = root; hit.hitSO = this; return(true); } return(false); }
protected void set_output_meshes(DMesh3 inner, DMesh3 outer) { InnerMesh = inner; OuterMesh = outer; AxisAlignedBox3d bounds = OuterMesh.CachedBounds; if (InnerMesh != null) { bounds.Contain(InnerMesh.CachedBounds); } // position center-top at origin Vector3d top = bounds.Center + bounds.Extents[1] * Vector3d.AxisY; if (InnerMesh != null) { MeshTransforms.Translate(InnerMesh, -top); } MeshTransforms.Translate(OuterMesh, -top); CombinedBounds = OuterMesh.CachedBounds; if (InnerMesh != null) { CombinedBounds.Contain(InnerMesh.CachedBounds); } if (InnerMesh != null) { var innerLoops = new MeshBoundaryLoops(InnerMesh); InnerLoop = innerLoops[0]; } var outerLoops = new MeshBoundaryLoops(OuterMesh); OuterLoop = outerLoops[0]; }
public static void DrawBoundingBox(AxisAlignedBox3d bounds, Transform transform) { var min = bounds.Min.toVector3(); var max = bounds.Max.toVector3(); var bottomRightBack = new Vector3(max.x, min.y, min.z); var bottomRightFront = new Vector3(max.x, max.y, min.z); var bottomLeftFront = new Vector3(min.x, max.y, min.z); var topRightBack = new Vector3(max.x, min.y, max.z); var topLeftBack = new Vector3(min.x, min.y, max.z); var topLeftFront = new Vector3(min.x, max.y, max.z); DrawLine(min, topLeftBack, transform); DrawLine(min, bottomLeftFront, transform); DrawLine(min, bottomRightBack, transform); DrawLine(max, bottomRightFront, transform); DrawLine(max, topLeftFront, transform); DrawLine(max, topRightBack, transform); DrawLine(topLeftBack, topRightBack, transform); DrawLine(bottomLeftFront, bottomRightFront, transform); DrawLine(topLeftFront, bottomLeftFront, transform); DrawLine(topRightBack, bottomRightBack, transform); DrawLine(topLeftBack, topLeftFront, transform); DrawLine(bottomRightBack, bottomRightFront, transform); }
public static DMesh3 MineCraft(DMesh3 mesh, int num_cells, out double scalefactor) { DMeshAABBTree3 spatial = new DMeshAABBTree3(mesh, autoBuild: true); AxisAlignedBox3d bounds = mesh.CachedBounds; double cellsize = bounds.MaxDim / num_cells; scalefactor = cellsize; ShiftGridIndexer3 indexer = new ShiftGridIndexer3(bounds.Min, cellsize); Bitmap3 bmp = new Bitmap3(new Vector3i(num_cells, num_cells, num_cells)); foreach (Vector3i idx in bmp.Indices()) { g3.Vector3d v = indexer.FromGrid(idx); if (spatial.IsInside(v)) { bmp.Set(idx, true); } else { bmp.Set(idx, false); } } VoxelSurfaceGenerator voxGen = new VoxelSurfaceGenerator(); voxGen.Voxels = bmp; voxGen.Generate(); DMesh3 voxMesh = voxGen.Meshes[0]; return(voxMesh); }
/// <summary> /// Slice the meshes and return the slice stack. /// </summary> public PlanarSliceStack Compute() { if (Meshes.Count == 0) { return(new PlanarSliceStack()); } Interval1d zrange = Interval1d.Empty; foreach (var meshinfo in Meshes) { zrange.Contain(meshinfo.bounds.Min.z); zrange.Contain(meshinfo.bounds.Max.z); } if (SetMinZValue != double.MinValue) { zrange.a = SetMinZValue; } // construct layers List <PlanarSlice> slice_list = new List <PlanarSlice>(); double cur_layer_z = zrange.a; int layer_i = 0; while (cur_layer_z < zrange.b) { double layer_height = get_layer_height(layer_i); double z = cur_layer_z; Interval1d zspan = new Interval1d(z, z + layer_height); if (SliceLocation == SliceLocations.EpsilonBase) { z += 0.01 * layer_height; } else if (SliceLocation == SliceLocations.MidLine) { z += 0.5 * layer_height; } PlanarSlice slice = SliceFactoryF(zspan, z, layer_i); slice.EmbeddedPathWidth = OpenPathDefaultWidthMM; slice_list.Add(slice); layer_i++; cur_layer_z += layer_height; } int NH = slice_list.Count; if (NH > MaxLayerCount) { throw new Exception("MeshPlanarSlicer.Compute: exceeded layer limit. Increase .MaxLayerCount."); } PlanarSlice[] slices = slice_list.ToArray(); // determine if we have crop objects bool have_crop_objects = false; foreach (var mesh in Meshes) { if (mesh.options.IsCropRegion) { have_crop_objects = true; } } // assume Resolve() takes 2x as long as meshes... TotalCompute = (Meshes.Count * NH) + (2 * NH); Progress = 0; // compute slices separately for each mesh for (int mi = 0; mi < Meshes.Count; ++mi) { if (Cancelled()) { break; } DMesh3 mesh = Meshes[mi].mesh; PrintMeshOptions mesh_options = Meshes[mi].options; // [TODO] should we hang on to this spatial? or should it be part of assembly? DMeshAABBTree3 spatial = new DMeshAABBTree3(mesh, true); AxisAlignedBox3d bounds = Meshes[mi].bounds; bool is_cavity = mesh_options.IsCavity; bool is_crop = mesh_options.IsCropRegion; bool is_support = mesh_options.IsSupport; bool is_closed = (mesh_options.IsOpen) ? false : mesh.IsClosed(); var useOpenMode = (mesh_options.OpenPathMode == OpenPathsModes.Default) ? DefaultOpenPathMode : mesh_options.OpenPathMode; // each layer is independent so we can do in parallel gParallel.ForEach(Interval1i.Range(NH), (i) => { if (Cancelled()) { return; } double z = slices[i].Z; if (z < bounds.Min.z || z > bounds.Max.z) { return; } // compute cut Polygon2d[] polys; PolyLine2d[] paths; compute_plane_curves(mesh, spatial, z, is_closed, out polys, out paths); // if we didn't hit anything, try again with jittered plane // [TODO] this could be better... if ((is_closed && polys.Length == 0) || (is_closed == false && polys.Length == 0 && paths.Length == 0)) { double jitterz = slices[i].LayerZSpan.Interpolate(0.75); compute_plane_curves(mesh, spatial, jitterz, is_closed, out polys, out paths); } if (is_closed) { // construct planar complex and "solids" // (ie outer polys and nested holes) PlanarComplex complex = new PlanarComplex(); foreach (Polygon2d poly in polys) { complex.Add(poly); } PlanarComplex.FindSolidsOptions options = PlanarComplex.FindSolidsOptions.Default; options.WantCurveSolids = false; options.SimplifyDeviationTolerance = 0.001; options.TrustOrientations = true; options.AllowOverlappingHoles = true; PlanarComplex.SolidRegionInfo solids = complex.FindSolidRegions(options); List <GeneralPolygon2d> solid_polygons = ApplyValidRegions(solids.Polygons); if (is_support) { add_support_polygons(slices[i], solid_polygons, mesh_options); } else if (is_cavity) { add_cavity_polygons(slices[i], solid_polygons, mesh_options); } else if (is_crop) { add_crop_region_polygons(slices[i], solid_polygons, mesh_options); } else { add_solid_polygons(slices[i], solid_polygons, mesh_options); } } else if (useOpenMode != OpenPathsModes.Ignored) { // [TODO] // - does not really handle clipped polygons properly, there will be an extra break somewhere... List <PolyLine2d> all_paths = new List <PolyLine2d>(paths); foreach (Polygon2d poly in polys) { all_paths.Add(new PolyLine2d(poly, true)); } List <PolyLine2d> open_polylines = ApplyValidRegions(all_paths); foreach (PolyLine2d pline in open_polylines) { if (useOpenMode == OpenPathsModes.Embedded) { slices[i].AddEmbeddedPath(pline); } else { slices[i].AddClippedPath(pline); } } } Interlocked.Increment(ref Progress); }); // end of parallel.foreach } // end mesh iter // resolve planar intersections, etc gParallel.ForEach(Interval1i.Range(NH), (i) => { if (Cancelled()) { return; } if (have_crop_objects && slices[i].InputCropRegions.Count == 0) { // don't resolve, we have fully cropped this layer } else { slices[i].Resolve(); } Interlocked.Add(ref Progress, 2); }); // discard spurious empty slices int last = slices.Length - 1; while (slices[last].IsEmpty && last > 0) { last--; } int first = 0; if (DiscardEmptyBaseSlices || have_crop_objects) { while (slices[first].IsEmpty && first < slices.Length) { first++; } } PlanarSliceStack stack = SliceStackFactoryF(); for (int k = first; k <= last; ++k) { stack.Add(slices[k]); } if (SupportMinZTips) { stack.AddMinZTipSupportPoints(MinZTipMaxDiam, MinZTipExtraLayers); } return(stack); }
protected virtual void update_level_set() { double unsigned_offset = Math.Abs(offset_distance); if (cached_sdf == null || unsigned_offset > cached_sdf_max_offset || grid_cell_size != cached_sdf.CellSize) { DMesh3 meshIn = MeshSource.GetDMeshUnsafe(); int exact_cells = (int)(unsigned_offset / grid_cell_size) + 1; // only use spatial DS if we are computing enough cells DMeshAABBTree3 use_spatial = GenerateClosedMeshOp.MeshSDFShouldUseSpatial( input_spatial, exact_cells, grid_cell_size, input_mesh_edge_stats.z); MeshSignedDistanceGrid sdf = new MeshSignedDistanceGrid(meshIn, grid_cell_size, use_spatial) { ExactBandWidth = exact_cells }; if (use_spatial != null) { sdf.NarrowBandMaxDistance = unsigned_offset + grid_cell_size; sdf.ComputeMode = MeshSignedDistanceGrid.ComputeModes.NarrowBand_SpatialFloodFill; } sdf.CancelF = is_invalidated; sdf.Compute(); if (is_invalidated()) { return; } cached_sdf = sdf; cached_sdf_max_offset = unsigned_offset; cached_sdf_bounds = meshIn.CachedBounds; } var iso = new DenseGridTrilinearImplicit(cached_sdf.Grid, cached_sdf.GridOrigin, cached_sdf.CellSize); MarchingCubes c = new MarchingCubes(); c.Implicit = iso; c.IsoValue = offset_distance; c.Bounds = cached_sdf_bounds; c.CubeSize = mesh_cell_size; c.Bounds.Expand(offset_distance + 3 * c.CubeSize); c.RootMode = MarchingCubes.RootfindingModes.LerpSteps; c.RootModeSteps = 5; c.CancelF = is_invalidated; c.Generate(); if (is_invalidated()) { return; } Reducer r = new Reducer(c.Mesh); r.FastCollapsePass(c.CubeSize * 0.5, 3, true); if (is_invalidated()) { return; } if (min_component_volume > 0) { MeshEditor.RemoveSmallComponents(c.Mesh, min_component_volume, min_component_volume); } if (is_invalidated()) { return; } ResultMesh = c.Mesh; }
/// <summary> /// this variant use a lazy-evaluation version of the grid, and continuation-MC, /// so the marching cubes pulls values from the grid that are evaluated on-the-fly. /// In theory this should be comparable or faster than the narrow-band version, /// practice it is 10-20% slower...?? possible reasons: /// - spinlock contention /// - lots of duplicate grid evaluations because CachingDenseGridTrilinearImplicit does not use locking /// /// However, because it can re-use grid values, changing the isovalue is /// *much* faster and so it makes sense if the mesh is not closed... /// </summary> protected virtual void update_winding_fast() { DMesh3 meshIn = MeshSource.GetDMeshUnsafe(); if (spatialPro == null || spatial_timestamp != meshIn.ShapeTimestamp) { spatialPro = new DMeshAABBTreePro(meshIn, true); spatialPro.FastWindingNumber(Vector3d.Zero); spatial_timestamp = meshIn.ShapeTimestamp; } if (is_invalidated()) { return; } if (cached_lazy_mwn_grid == null || grid_cell_size != cached_lazy_mwn_grid.CellSize) { // figure out origin & dimensions AxisAlignedBox3d bounds = meshIn.CachedBounds; float fBufferWidth = 2 * (float)grid_cell_size; Vector3d origin = (Vector3f)bounds.Min - fBufferWidth * Vector3f.One; Vector3f max = (Vector3f)bounds.Max + fBufferWidth * Vector3f.One; int ni = (int)((max.x - origin.x) / (float)grid_cell_size) + 1; int nj = (int)((max.y - origin.y) / (float)grid_cell_size) + 1; int nk = (int)((max.z - origin.z) / (float)grid_cell_size) + 1; var grid = new CachingDenseGridTrilinearImplicit(origin, grid_cell_size, new Vector3i(ni, nj, nk)); grid.AnalyticF = new WindingField(spatialPro); cached_lazy_mwn_grid = grid; cached_mwn_bounds = meshIn.CachedBounds; } WindingFieldImplicit iso = new WindingFieldImplicit(cached_lazy_mwn_grid, winding_iso); MarchingCubesPro c = new MarchingCubesPro(); c.Implicit = iso; c.Bounds = cached_mwn_bounds; c.CubeSize = mesh_cell_size; c.Bounds.Expand(3 * c.CubeSize); c.RootMode = MarchingCubesPro.RootfindingModes.Bisection; c.RootModeSteps = 10; c.CancelF = is_invalidated; c.GenerateContinuation(meshIn.Vertices()); if (is_invalidated()) { return; } Reducer r = new Reducer(c.Mesh); r.FastCollapsePass(c.CubeSize * 0.5, 3, true); if (is_invalidated()) { return; } if (min_component_volume > 0) { MeshEditor.RemoveSmallComponents(c.Mesh, min_component_volume, min_component_volume); } if (is_invalidated()) { return; } // reproject - if we want to do this, we need to create spatial and meshIn above! gParallel.ForEach(c.Mesh.VertexIndices(), (vid) => { if (is_invalidated()) { return; } Vector3d v = c.Mesh.GetVertex(vid); int tid = spatialPro.FindNearestTriangle(v, grid_cell_size * MathUtil.SqrtTwo); if (tid != DMesh3.InvalidID) { var query = MeshQueries.TriangleDistance(meshIn, tid, v); if (v.Distance(query.TriangleClosest) < grid_cell_size) { c.Mesh.SetVertex(vid, query.TriangleClosest); } } }); if (is_invalidated()) { return; } ResultMesh = c.Mesh; }
/// <summary> /// Sample analytic winding number into grid in narrow-band around target isovalue, /// and then extract using marching cubes. /// /// TODO: don't need to discard current grid when isovalue changes, just need to /// re-run the front propagation part of mwn.Compute()! /// If this is done, then use this instead of update_winding_fast() for open meshes /// </summary> protected virtual void update_winding() { DMesh3 meshIn = MeshSource.GetDMeshUnsafe(); if (spatialPro == null || spatial_timestamp != meshIn.ShapeTimestamp) { spatialPro = new DMeshAABBTreePro(meshIn, true); spatialPro.FastWindingNumber(Vector3d.Zero); spatial_timestamp = meshIn.ShapeTimestamp; } if (is_invalidated()) { return; } if (cached_mwn_grid == null || grid_cell_size != cached_mwn_grid.CellSize || (float)winding_iso != cached_mwn_grid.IsoValue) { Func <Vector3d, double> fastWN = (q) => { return(spatialPro.FastWindingNumber(q)); }; var mwn = new MeshScalarSamplingGrid(meshIn, grid_cell_size, fastWN) { IsoValue = (float)winding_iso }; mwn.CancelF = is_invalidated; mwn.Compute(); if (is_invalidated()) { return; } cached_mwn_grid = mwn; cached_mwn_bounds = meshIn.CachedBounds; } MarchingCubes c = new MarchingCubes(); c.Implicit = new SampledGridImplicit(cached_mwn_grid); c.IsoValue = 0.0; c.Bounds = cached_mwn_bounds; c.CubeSize = mesh_cell_size; c.Bounds.Expand(3 * c.CubeSize); c.RootMode = MarchingCubes.RootfindingModes.Bisection; c.RootModeSteps = 10; c.CancelF = is_invalidated; c.Generate(); if (is_invalidated()) { return; } Reducer r = new Reducer(c.Mesh); r.FastCollapsePass(c.CubeSize * 0.5, 3, true); if (is_invalidated()) { return; } if (min_component_volume > 0) { MeshEditor.RemoveSmallComponents(c.Mesh, min_component_volume, min_component_volume); } if (is_invalidated()) { return; } // reproject - if we want to do this, we need to create spatial and meshIn above! gParallel.ForEach(c.Mesh.VertexIndices(), (vid) => { if (is_invalidated()) { return; } Vector3d v = c.Mesh.GetVertex(vid); int tid = spatialPro.FindNearestTriangle(v, grid_cell_size * MathUtil.SqrtTwo); if (tid != DMesh3.InvalidID) { var query = MeshQueries.TriangleDistance(meshIn, tid, v); if (v.Distance(query.TriangleClosest) < grid_cell_size) { c.Mesh.SetVertex(vid, query.TriangleClosest); } } }); if (is_invalidated()) { return; } ResultMesh = c.Mesh; }
static void run_single_process() { int done_count = 0; int MAX_COUNT = 10000; bool VERBOSE = false; TimeSpan TIMEOUT = TimeSpan.FromSeconds(30); int failed_count = 0; double MAX_DIM_MM = 50; int MAX_TRI_COUNT = 250000; HashSet <string> completed = File.Exists(CACHE_FILENAME) ? new HashSet <string>(File.ReadAllLines(CACHE_FILENAME)) : new HashSet <string>(); string[] files = Directory.GetFiles("E:\\Thingi10K\\closed"); SafeListBuilder <string> result_strings = new SafeListBuilder <string>(); SafeListBuilder <string> processed_files = new SafeListBuilder <string>(); gParallel.ForEach(files, (filename) => { int i = done_count; if (i > MAX_COUNT) { return; } Interlocked.Increment(ref done_count); if (i % 10 == 0) { System.Console.WriteLine("started {0} / {1}", i, files.Length); } if (completed.Contains(filename)) { return; } // save progress on this run if (i % 10 == 0) { write_output(result_strings); lock (completed) { write_completed(completed, CACHE_FILENAME); } } DMesh3 mesh = StandardMeshReader.ReadMesh(filename); AxisAlignedBox3d bounds = mesh.CachedBounds; MeshTransforms.Scale(mesh, MAX_DIM_MM / bounds.MaxDim); Vector3d basePt = mesh.CachedBounds.Point(0, 0, -1); MeshTransforms.Translate(mesh, -basePt); if (mesh.TriangleCount > MAX_TRI_COUNT) { Reducer r = new Reducer(mesh); r.ReduceToTriangleCount(MAX_TRI_COUNT); mesh = new DMesh3(mesh, true); } StringBuilder builder = new StringBuilder(); builder.Append(filename); builder.Append(','); builder.Append(mesh.TriangleCount.ToString()); builder.Append(','); var start = DateTime.Now; if (VERBOSE) { System.Console.WriteLine(builder.ToString()); } if (VERBOSE) { System.Console.WriteLine(mesh.CachedBounds.ToString()); } GCodeInfo gcinfo = GenerateGCodeForFileWithTimeout2(filename, TIMEOUT); if (gcinfo.exception != null) { System.Console.WriteLine(filename + " : " + gcinfo.exception.Message); Interlocked.Increment(ref failed_count); } if (gcinfo.completed) { builder.Append("OK"); } else if (gcinfo.completed == false && gcinfo.timed_out) { builder.Append("TIMEOUT"); } else if (gcinfo.completed == false) { builder.Append("FAILED"); } builder.Append(','); var end = DateTime.Now; builder.Append(((int)(end - start).TotalSeconds).ToString()); builder.Append(','); builder.Append(gcinfo.SliceCount.ToString()); builder.Append(','); builder.Append(gcinfo.GCodeLines.ToString()); builder.Append(','); builder.Append(gcinfo.GCodeBytes.ToString()); builder.Append(','); builder.Append(gcinfo.TotalLength.ToString()); builder.Append(','); if (VERBOSE) { System.Console.WriteLine(builder.ToString()); } result_strings.SafeAdd(builder.ToString()); lock (completed) { completed.Add(filename); } }); write_output(result_strings); }
static void Main(string[] args) { GCodeInfo info = new GCodeInfo(); string filename = args[0]; DMesh3 mesh = StandardMeshReader.ReadMesh(filename); AxisAlignedBox3d bounds = mesh.CachedBounds; MeshTransforms.Scale(mesh, MAX_DIM_MM / bounds.MaxDim); Vector3d basePt = mesh.CachedBounds.Point(0, 0, -1); MeshTransforms.Translate(mesh, -basePt); if (mesh.TriangleCount > MAX_TRI_COUNT) { Reducer r = new Reducer(mesh); r.ReduceToTriangleCount(MAX_TRI_COUNT); mesh = new DMesh3(mesh, true); } var start = DateTime.Now; bool ENABLE_SUPPORT_ZSHIFT = true; try { // configure settings MakerbotSettings settings = new MakerbotSettings(Makerbot.Models.Replicator2); //MonopriceSettings settings = new MonopriceSettings(Monoprice.Models.MP_Select_Mini_V2); //PrintrbotSettings settings = new PrintrbotSettings(Printrbot.Models.Plus); settings.ExtruderTempC = 200; settings.Shells = 2; settings.InteriorSolidRegionShells = 0; settings.SparseLinearInfillStepX = 10; settings.ClipSelfOverlaps = false; settings.GenerateSupport = true; settings.EnableSupportShell = true; PrintMeshAssembly meshes = new PrintMeshAssembly(); meshes.AddMesh(mesh); // slice meshes MeshPlanarSlicerPro slicer = new MeshPlanarSlicerPro() { LayerHeightMM = settings.LayerHeightMM, SliceFactoryF = PlanarSlicePro.FactoryF }; slicer.Add(meshes); PlanarSliceStack slices = slicer.Compute(); info.SliceCount = slices.Count; info.SliceBounds = slices.Bounds; // run print generator SingleMaterialFFFPrintGenPro printGen = new SingleMaterialFFFPrintGenPro(meshes, slices, settings); if (ENABLE_SUPPORT_ZSHIFT) { printGen.LayerPostProcessor = new SupportConnectionPostProcessor() { ZOffsetMM = 0.2f } } ; printGen.AccumulatePathSet = true; printGen.Generate(); GCodeFile genGCode = printGen.Result; info.PathBounds = printGen.AccumulatedPaths.Bounds; info.ExtrudeBounds = printGen.AccumulatedPaths.ExtrudeBounds; info.TotalLength = CurveUtils.ArcLength(printGen.AccumulatedPaths.AllPositionsItr()); info.GCodeLines = genGCode.LineCount; // write to in-memory string StandardGCodeWriter writer = new StandardGCodeWriter(); using (MemoryStream membuf = new MemoryStream()) { using (StreamWriter w = new StreamWriter(membuf)) { writer.WriteFile(genGCode, w); info.GCodeBytes = (int)membuf.Length; } } // try to force destructor error printGen = null; genGCode = null; GC.Collect(); } catch (Exception e) { System.Console.WriteLine("EXCEPTION:" + e.Message); return; } var end = DateTime.Now; int seconds = (int)(end - start).TotalSeconds; System.Console.WriteLine("{0},{1},{2},{3},{4},{5},{6},{7},", filename, mesh.TriangleCount, "OK", seconds, info.SliceCount, info.GCodeLines, info.GCodeBytes, (int)info.TotalLength); }