/// <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 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)); }
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); }