protected virtual List <GeneralPolygon2d> make_solid(GeneralPolygon2d poly, bool bIsSupportSolid) { // always do a self-union of outer polygon. This allows Clipper to clean up many // problems in input polygons, eg self-intersections and other junk GeneralPolygon2d gouter = new GeneralPolygon2d(poly.Outer); List <GeneralPolygon2d> resolvedSolid = ClipperUtil.Union(gouter, gouter, MIN_AREA); // solid may contain overlapping holes. We need to resolve these before continuing, // otherwise those overlapping regions will be filled by Clipper even/odd rules foreach (Polygon2d hole in poly.Holes) { GeneralPolygon2d holePoly = new GeneralPolygon2d(hole); resolvedSolid = ClipperUtil.PolygonBoolean(resolvedSolid, holePoly, ClipperUtil.BooleanOp.Difference, MIN_AREA); } if (bIsSupportSolid == false && Thickened != null) { // Subtract away any clearance solids foreach (var pair in Thickened) { if (pair.Key != poly) { resolvedSolid = ClipperUtil.Difference(resolvedSolid, pair.Value); } } } return(filter_solids(resolvedSolid)); }
virtual protected void cache_brim_polys() { combined_solid = new List <GeneralPolygon2d>(); combined_support = new List <GeneralPolygon2d>(); subtract = new List <GeneralPolygon2d>(); Frame3f cutPlane = new Frame3f((float)layer_height * 0.5f * Vector3f.AxisY, Vector3f.AxisY); foreach (var so in CC.Objects.PrintMeshes) { if (so.Settings.ObjectType == PrintMeshSettings.ObjectTypes.Ignored) { continue; } SOSectionPlane section = new SOSectionPlane(so); section.UpdateSection(cutPlane, CoordSpace.SceneCoords); List <GeneralPolygon2d> solids = section.GetSolids(); // [TODO] should subtract holes explicitly here, like we do in slicer? if (so.Settings.ObjectType == PrintMeshSettings.ObjectTypes.Cavity) { subtract = ClipperUtil.Union(solids, subtract); } else if (so.Settings.ObjectType == PrintMeshSettings.ObjectTypes.Support) { combined_support = ClipperUtil.Union(solids, combined_support); } else if (so.Settings.ObjectType == PrintMeshSettings.ObjectTypes.Solid) { combined_solid = ClipperUtil.Union(solids, combined_solid); } } if (subtract.Count > 0) { combined_solid = ClipperUtil.Difference(combined_solid, subtract); } combined_all = ClipperUtil.Union(combined_solid, combined_support); combined_all = CurveUtils2.FilterDegenerate(combined_all, 0.001); foreach (var poly in combined_all) { poly.Simplify(path_width * 0.02); } }
protected override List <GeneralPolygon2d> make_solid(GeneralPolygon2d poly, bool bIsSupportSolid) { List <GeneralPolygon2d> solid = base.make_solid(poly, bIsSupportSolid); if (bIsSupportSolid == false && Thickened != null) { // subtract clearance solids foreach (var pair in Thickened) { if (pair.Key != poly) { solid = ClipperUtil.Difference(solid, pair.Value); } } } return(solid); }
protected virtual List <GeneralPolygon2d> remove_cavity(List <GeneralPolygon2d> solids, GeneralPolygon2d cavity) { double offset = 0; if (Cavity_Clearances.ContainsKey(cavity)) { offset = Cavity_Clearances[cavity]; } if (Cavity_Offsets.ContainsKey(cavity)) { offset += Cavity_Offsets[cavity]; } if (Math.Abs(offset) > 0.0001) { var offset_cavities = ClipperUtil.MiterOffset(cavity, offset, MIN_AREA); return(ClipperUtil.Difference(solids, offset_cavities, MIN_AREA)); } else { return(ClipperUtil.Difference(solids, cavity, MIN_AREA)); } }
/// <summary> /// Convert assembly of polygons, polylines, etc, into a set of printable solids and paths /// </summary> public virtual void Resolve() { // combine solids, process largest-to-smallest if (InputSolids.Count > 0) { GeneralPolygon2d[] solids = InputSolids.ToArray(); solids = process_input_polys_before_sort(solids); // sort by decreasing weight double[] weights = new double[solids.Length]; for (int i = 0; i < solids.Length; ++i) { weights[i] = sorting_weight(solids[i]); } Array.Sort(weights, solids); Array.Reverse(solids); solids = process_input_polys_after_sort(solids); Solids = new List <GeneralPolygon2d>(); for (int k = 0; k < solids.Length; ++k) { // convert this polygon into the solid we want to use List <GeneralPolygon2d> resolvedSolid = make_solid(solids[k], false); // now union in with accumulated solids if (Solids.Count == 0) { Solids.AddRange(resolvedSolid); } else { Solids = combine_solids(Solids, resolvedSolid); } } } // subtract input cavities foreach (var cavity in InputCavities) { Solids = remove_cavity(Solids, cavity); } // subtract thickened embedded paths from solids if (EmbeddedPaths.Count > 0 && EmbeddedPathWidth == 0) { throw new Exception("PlanarSlice.Resolve: must set embedded path width!"); } foreach (var path in EmbeddedPaths) { Polygon2d thick_path = make_thickened_path(path, EmbeddedPathWidth); Solids = ClipperUtil.Difference(Solids, new GeneralPolygon2d(thick_path), MIN_AREA); Paths.Add(path); } // cleanup Solids = filter_solids(Solids); // subtract solids from clipped paths foreach (var path in ClippedPaths) { List <PolyLine2d> clipped = ClipperUtil.ClipAgainstPolygon(Solids, path); foreach (var cp in clipped) { Paths.Add(cp); } } // combine support solids, while also subtracting print solids and thickened paths if (InputSupportSolids.Count > 0) { // make assembly of path solids // [TODO] do we need to boolean these? List <GeneralPolygon2d> path_solids = null; if (Paths.Count > 0) { path_solids = new List <GeneralPolygon2d>(); foreach (var path in Paths) { path_solids.Add(new GeneralPolygon2d(make_thickened_path(path, EmbeddedPathWidth))); } } foreach (var solid in InputSupportSolids) { // convert this polygon into the solid we want to use List <GeneralPolygon2d> resolved = make_solid(solid, true); // now subtract print solids resolved = ClipperUtil.PolygonBoolean(resolved, Solids, ClipperUtil.BooleanOp.Difference, MIN_AREA); // now subtract paths if (path_solids != null) { resolved = ClipperUtil.PolygonBoolean(resolved, path_solids, ClipperUtil.BooleanOp.Difference, MIN_AREA); } // now union in with accumulated support solids if (SupportSolids.Count == 0) { SupportSolids.AddRange(resolved); } else { SupportSolids = ClipperUtil.PolygonBoolean(SupportSolids, resolved, ClipperUtil.BooleanOp.Union, MIN_AREA); } } SupportSolids = filter_solids(SupportSolids); } // apply crop regions if (InputCropRegions.Count > 0) { // combine crop regions var CropRegions = make_solid(InputCropRegions[0], false); for (int k = 1; k < InputCropRegions.Count; ++k) { CropRegions = combine_solids(CropRegions, make_solid(InputCropRegions[k], false)); } Solids = ClipperUtil.Intersection(CropRegions, Solids, MIN_AREA); Solids = filter_solids(Solids); List <PolyLine2d> cropped_paths = new List <PolyLine2d>(); foreach (var path in Paths) { cropped_paths.AddRange(ClipperUtil.ClipAgainstPolygon(CropRegions, path, true)); } // TODO: filter paths SupportSolids = ClipperUtil.Intersection(CropRegions, SupportSolids, MIN_AREA); SupportSolids = filter_solids(SupportSolids); } }
virtual public void PreRender() { if (in_shutdown()) { return; } if (parameters_dirty) { // offset List <GeneralPolygon2d> offset = ClipperUtil.RoundOffset(combined_all, offset_distance); // aggressively simplify after round offset... foreach (var poly in offset) { poly.Simplify(path_width); } // subtract initial and add tiny gap so these don't get merged by slicer if (SubtractSolids) { offset = ClipperUtil.Difference(offset, combined_solid); offset = ClipperUtil.MiterOffset(offset, -path_width * 0.1); } offset = CurveUtils2.FilterDegenerate(offset, 0.001); foreach (var poly in offset) { poly.Simplify(path_width * 0.02); } DMesh3 mesh = new DMesh3(); MeshEditor editor = new MeshEditor(mesh); foreach (var poly in offset) { TriangulatedPolygonGenerator polygen = new TriangulatedPolygonGenerator() { Polygon = poly }; editor.AppendMesh(polygen.Generate().MakeDMesh()); } MeshTransforms.ConvertZUpToYUp(mesh); if (mesh.TriangleCount > 0) { MeshExtrudeMesh extrude = new MeshExtrudeMesh(mesh); extrude.ExtrudedPositionF = (v, n, vid) => { return(v + Layers * layer_height * Vector3d.AxisY); }; extrude.Extrude(); MeshTransforms.Translate(mesh, -mesh.CachedBounds.Min.y * Vector3d.AxisY); } PreviewSO.ReplaceMesh(mesh, true); //Vector3d translate = scene_bounds.Point(1, -1, 1); //translate.x += spiral.Bounds.Width + PathWidth; //Frame3f sceneF = Frame3f.Identity.Translated((Vector3f)translate); //PreviewSO.SetLocalFrame(sceneF, CoordSpace.SceneCoords); parameters_dirty = false; } }
protected virtual List <GeneralPolygon2d> remove_cavity(List <GeneralPolygon2d> solids, GeneralPolygon2d cavity) { return(ClipperUtil.Difference(solids, cavity, MIN_AREA)); }