public static CSG hull(List <IVector3d> points, PropertyStorage storage) { Point3d[] hullPoints = points.Select(vec => new Point3d(vec.x(), vec.y(), vec.z())).ToArray(); Hull hull = new Hull(); hull.Build(hullPoints); hull.Triangulate(); int[][] faces = hull.GetFaces(); List <Polygon> polygons = new List <Polygon>(); List <IVector3d> vertices = new List <IVector3d>(); foreach (int[] verts in faces) { foreach (int i in verts) { vertices.Add(points[hull.GetVertexPointIndices()[i]]); } polygons.Add(Polygon.fromPoints(vertices, storage)); vertices.Clear(); } return(CSG.fromPolygons(polygons)); }
/// <summary> /// Returns a triangulated version of this polygon. /// </summary> /// <returns>triangles</returns> /// public List <Polygon> toTriangles() { List <Polygon> result = new List <Polygon>(); if (this.vertices.Count >= 3) { // TODO: improve the triangulation? // // If our polygon has more vertices, create // multiple triangles: Vertex firstVertexStl = this.vertices[0]; for (int i = 0; i < this.vertices.Count - 2; i++) { // create triangle Polygon polygon = Polygon.fromPoints( firstVertexStl.pos, this.vertices[i + 1].pos, this.vertices[i + 2].pos ); result.Add(polygon); } } return(result); }
/// /// Loads a CSG from stl. /// /// <param name="path">file path</param> /// <returns>CSG</returns> /// @throws IOException if loading failed /// public static CSG file(string path) { var solid = STLSolid.CreateFromFile(path); List <Polygon> polygons = new List <Polygon>(); List <IVector3d> vertices = new List <IVector3d>(); foreach (var facet in solid.Facets) { vertices.Add(Vector3d.xyz(facet.OuterLoop.V0.X, facet.OuterLoop.V0.Y, facet.OuterLoop.V0.Z)); vertices.Add(Vector3d.xyz(facet.OuterLoop.V1.X, facet.OuterLoop.V1.Y, facet.OuterLoop.V1.Z)); vertices.Add(Vector3d.xyz(facet.OuterLoop.V2.X, facet.OuterLoop.V2.Y, facet.OuterLoop.V2.Z)); if (vertices.Count == 3) { polygons.Add(Polygon.fromPoints(vertices)); vertices = new List <IVector3d>(); } } //foreach (IVector3d p in loader.parse(path)) //{ // vertices.Add(p.clone()); // if (vertices.Count == 3) // { // polygons.Add(Polygon.fromPoints(vertices)); // vertices = new List<IVector3d>(); // } //} return(CSG.fromPolygons(new PropertyStorage(), polygons)); }
public List <Polygon> toPolygons() { Func <int, IVector3d> indexToPoint = i => points[i].clone(); Func <List <int>, Polygon> faceListToPolygon = faceList => Polygon.fromPoints(faceList.Select(indexToPoint).ToList(), properties); return(faces.Select(faceListToPolygon).ToList()); }
static List <IVector3d> toCW(List <IVector3d> points) { List <IVector3d> result = new List <IVector3d>(points); if (isCCW(Polygon.fromPoints(result))) { result.Reverse(); } return(result); }
/// <summary> /// Combines two polygons into one CSG object. Polygons p1 and p2 are treated as top and /// bottom of a tube segment with p1 and p2 as the profile. <b>Note:</b> both polygons must have the /// same number of vertices. This method does not guarantee intersection-free CSGs. It is in the /// responsibility of the caller to ensure that the orientation of p1 and p2 allow for /// intersection-free combination of both. /// </summary> /// <param name="p1">first polygon</param> /// <param name="p2">second polygon</param> /// <param name="bottom">defines whether to close the bottom of the tube</param> /// <param name="top">defines whether to close the top of the tube</param> /// <returns>List of polygons</returns> /// public static List <Polygon> combine(Polygon p1, Polygon p2, bool bottom, bool top) { List <Polygon> newPolygons = new List <Polygon>(); if (p1.vertices.Count != p2.vertices.Count) { throw new Exception("Polygons must have the same number of vertices"); } int numVertices = p1.vertices.Count; if (bottom) { newPolygons.Add(p1.flipped()); } for (int i = 0; i < numVertices; i++) { int nexti = (i + 1) % numVertices; IVector3d bottomV1 = p1.vertices[i].pos; IVector3d topV1 = p2.vertices[i].pos; IVector3d bottomV2 = p1.vertices[nexti].pos; IVector3d topV2 = p2.vertices[nexti].pos; List <IVector3d> pPoints; pPoints = new List <IVector3d> { bottomV2, topV2, topV1 }; newPolygons.Add(Polygon.fromPoints(pPoints, p1.getStorage())); pPoints = new List <IVector3d> { bottomV2, topV1, bottomV1 }; newPolygons.Add(Polygon.fromPoints(pPoints, p1.getStorage())); } if (top) { newPolygons.Add(p2); } return(newPolygons); }
private static Polygon toPolygon(List <IVector3d> points, Plane plane) { // List<Vector3d> points = edges.().Select(e => e.p1.pos). // .ToList(); Polygon p = Polygon.fromPoints(points); p.vertices.ForEach(vertex => vertex.normal = plane.normal.clone()); // TODO Find out the meaning of foEachOrdered //p.vertices.forEachOrdered(vertex => { // vertex.normal = plane.normal.clone(); //}); // // we try to detect wrong orientation by comparing normals // if (p.plane.normal.angle(plane.normal) > 0.1) { // p.flip(); // } return(p); }
private static CSG extrude(IVector3d dir, Polygon polygon1) { List <Polygon> newPolygons = new List <Polygon>(); if (dir.z() < 0) { throw new ArgumentException("z < 0 currently not supported for extrude: " + dir); } newPolygons.AddRange(PolygonUtil.concaveToConvex(polygon1)); Polygon polygon2 = polygon1.translated(dir); int numvertices = polygon1.vertices.Count; for (int i = 0; i < numvertices; i++) { int nexti = (i + 1) % numvertices; IVector3d bottomV1 = polygon1.vertices[i].pos; IVector3d topV1 = polygon2.vertices[i].pos; IVector3d bottomV2 = polygon1.vertices[nexti].pos; IVector3d topV2 = polygon2.vertices[nexti].pos; List <IVector3d> pPoints = new List <IVector3d> { bottomV2, topV2, topV1, bottomV1 }; newPolygons.Add(Polygon.fromPoints(pPoints, polygon1.getStorage())); } polygon2 = polygon2.flipped(); List <Polygon> topPolygons = PolygonUtil.concaveToConvex(polygon2); newPolygons.AddRange(topPolygons); return(CSG.fromPolygons(newPolygons)); }
/// <summary> /// Extrudes the specified path (convex or concave polygon without holes or /// intersections, specified in CCW) into the specified direction. /// </summary> /// <param name="dir">direction</param> /// <param name="points">path (convex or concave polygon without holes or /// intersections)</param> /// /// <returns>a list containing the extruded polygon</returns> /// public static List <Polygon> points(IVector3d dir, bool top, bool bottom, params IVector3d[] points) { return(extrude(dir, Polygon.fromPoints(toCCW(points.ToList())), top, bottom)); }
/// </summary> /// Extrudes the specified path (convex or concave polygon without holes or /// intersections, specified in CCW) into the specified direction. /// </summary> /// <param name="dir">direction</param> /// <param name="points">path (convex or concave polygon without holes or /// intersections)</param> /// /// <returns>a CSG object that consists of the extruded polygon</returns> /// public static CSG points(IVector3d dir, List <IVector3d> points) { List <IVector3d> newList = new List <IVector3d>(points); return(extrude(dir, Polygon.fromPoints(toCCW(newList)))); }
/// <summary> /// Extrudes the specified path (convex or concave polygon without holes or /// intersections, specified in CCW) into the specified direction. /// </summary> /// <param name="dir">direction</param> /// <param name="points">path (convex or concave polygon without holes or /// intersections)</param> /// /// <returns>a CSG object that consists of the extruded polygon</returns> /// public static CSG points(IVector3d dir, params IVector3d[] points) { return(extrude(dir, Polygon.fromPoints(toCCW(points.ToList())))); }
private static List <Polygon> extrude(IVector3d dir, Polygon polygon1, bool top, bool bottom) { List <Polygon> newPolygons = new List <Polygon>(); if (bottom) { newPolygons.AddRange(PolygonUtil.concaveToConvex(polygon1)); } Polygon polygon2 = polygon1.translated(dir); Transform rot = Transform.unity(); IVector3d a = polygon2.getPlane().getNormal().normalized(); IVector3d b = dir.normalized(); IVector3d c = a.crossed(b); double l = c.magnitude(); // sine of angle if (l > 1e-9) { IVector3d axis = c.times(1.0 / l); double angle = a.angle(b); double sx = 0; double sy = 0; double sz = 0; int n = polygon2.vertices.Count; foreach (Vertex v in polygon2.vertices) { sx += v.pos.x(); sy += v.pos.y(); sz += v.pos.z(); } IVector3d center = Vector3d.xyz(sx / n, sy / n, sz / n); rot = rot.rot(center, axis, angle * Math.PI / 180.0); foreach (Vertex v in polygon2.vertices) { v.pos = rot.transform(v.pos); } } int numvertices = polygon1.vertices.Count; for (int i = 0; i < numvertices; i++) { int nexti = (i + 1) % numvertices; IVector3d bottomV1 = polygon1.vertices[i].pos; IVector3d topV1 = polygon2.vertices[i].pos; IVector3d bottomV2 = polygon1.vertices[nexti].pos; IVector3d topV2 = polygon2.vertices[nexti].pos; List <IVector3d> pPoints = new List <IVector3d> { bottomV2, topV2, topV1, bottomV1 }; newPolygons.Add(Polygon.fromPoints(pPoints, polygon1.getStorage())); } polygon2 = polygon2.flipped(); List <Polygon> topPolygons = PolygonUtil.concaveToConvex(polygon2); if (top) { newPolygons.AddRange(topPolygons); } return(newPolygons); }
/// <summary> /// Extrudes the specified path (convex or concave polygon without holes or /// intersections, specified in CCW) into the specified direction. /// </summary> /// <param name="dir">direction</param> /// <param name="points1">path (convex or concave polygon without holes or /// intersections)</param> /// <param name="points1">path (convex or concave polygon without holes or /// intersections)</param> /// /// <returns>a list containing the extruded polygon</returns> /// public static List <Polygon> points(IVector3d dir, bool top, bool bottom, List <IVector3d> points1) { List <IVector3d> newList1 = new List <IVector3d>(points1); return(extrude(dir, Polygon.fromPoints(toCCW(newList1)), top, bottom)); }
/// <summary> /// Returns a list of all boundary paths. /// </summary> /// <param name="boundaryEdges">boundary edges (all paths must be closed)</param> /// <returns></returns> private static List <Polygon> boundaryPaths(List <Edge> boundaryEdges) { List <Polygon> result = new List <Polygon>(); bool[] used = new bool[boundaryEdges.Count]; int startIndex = 0; Edge edge = boundaryEdges[startIndex]; used[startIndex] = true; startIndex = 1; while (startIndex > 0) { List <IVector3d> boundaryPath = new List <IVector3d>(); while (true) { Edge finalEdge = edge; boundaryPath.Add(finalEdge.p1.pos); Console.Out.Write("edge: " + edge.p2.pos); Edge nextEdgeResult = boundaryEdges. Where(e => finalEdge.p2.Equals(e.p1)).First(); if (nextEdgeResult == null) { Console.Out.WriteLine("ERROR: unclosed path:" + " no edge found with " + finalEdge.p2); break; } Edge nextEdge = nextEdgeResult; int nextEdgeIndex = boundaryEdges.IndexOf(nextEdge); if (used[nextEdgeIndex]) { break; } edge = nextEdge; Console.Out.WriteLine("=> edge: " + edge.p1.pos); used[nextEdgeIndex] = true; } if (boundaryPath.Count < 3) { break; } result.Add(Polygon.fromPoints(boundaryPath)); startIndex = nextUnused(used); if (startIndex > 0) { edge = boundaryEdges[startIndex]; used[startIndex] = true; } } Console.Out.WriteLine("paths: " + result.Count); return(result); }