Solid UnionSub(Solid csg, bool retesselate, bool canonicalize) { if (!MayOverlap(csg)) { return(UnionForNonIntersecting(csg)); } else { var a = new Tree(Bounds, Polygons); var b = new Tree(csg.Bounds, csg.Polygons); a.ClipTo(b, false); b.ClipTo(a); b.Invert(); b.ClipTo(a); b.Invert(); var newpolygons = new List <Polygon>(a.AllPolygons()); newpolygons.AddRange(b.AllPolygons()); var result = Solid.FromPolygons(newpolygons); result.Properties = Properties.Merge(csg.Properties); if (retesselate) { result = result.Retesselated(); } if (canonicalize) { result = result.Canonicalized(); } return(result); } }
public static Solid Cube(CubeOptions options) { var c = options.Center; var r = options.Radius.Abs; // negative radii make no sense if (r.X == 0.0 || r.Y == 0.0 || r.Z == 0.0) { return(new Solid()); } var result = Solid.FromPolygons(cubeData.Select(info => { //var normal = new Vector3D(info[1]); //var plane = new Plane(normal, 1); var vertices = info[0].Select(i => { var pos = new Vector3D( c.X + r.X * (2 * ((i & 1) != 0 ? 1 : 0) - 1), c.Y + r.Y * (2 * ((i & 2) != 0 ? 1 : 0) - 1), c.Z + r.Z * (2 * ((i & 4) != 0 ? 1 : 0) - 1)); return(new Vertex(pos)); }); return(new Polygon(vertices.ToList())); }).ToList()); return(result); }
Solid IntersectSub(Solid csg, bool retesselate, bool canonicalize) { var a = new Tree(Bounds, Polygons); var b = new Tree(csg.Bounds, csg.Polygons); a.Invert(); b.ClipTo(a); b.Invert(); a.ClipTo(b); b.ClipTo(a); a.AddPolygons(b.AllPolygons()); a.Invert(); var result = Solid.FromPolygons(a.AllPolygons()); result.Properties = Properties.Merge(csg.Properties); if (retesselate) { result = result.Retesselated(); } if (canonicalize) { result = result.Canonicalized(); } return(result); }
Solid Retesselated() { if (IsRetesselated) { return(this); } else { var csg = this; var polygonsPerPlane = new Dictionary <string, List <Polygon> >(); var isCanonicalized = csg.IsCanonicalized; var fuzzyFactory = new FuzzyCsgFactory(); foreach (var polygon in csg.Polygons) { var plane = polygon.Plane; var shared = polygon.Shared; if (!isCanonicalized) { plane = fuzzyFactory.GetPlane(plane); shared = fuzzyFactory.GetPolygonShared(shared); } var tag = plane.Tag + "/" + shared.Tag; List <Polygon> ppp; if (polygonsPerPlane.TryGetValue(tag, out ppp)) { ppp.Add(polygon); } else { ppp = new List <Polygon>(); ppp.Add(polygon); polygonsPerPlane.Add(tag, ppp); } } var destpolygons = new List <Polygon>(); foreach (var planetag in polygonsPerPlane) { var sourcepolygons = planetag.Value; if (sourcepolygons.Count < 2) { destpolygons.AddRange(sourcepolygons); } else { var retesselatedpolygons = new List <Polygon>(); Solid.RetesselateCoplanarPolygons(sourcepolygons, retesselatedpolygons); destpolygons.AddRange(retesselatedpolygons); } } var result = Solid.FromPolygons(destpolygons); result.IsRetesselated = true; result.Properties = Properties; return(result); } }
Solid UnionForNonIntersecting(Solid csg) { var newpolygons = new List <Polygon>(Polygons); newpolygons.AddRange(csg.Polygons); var result = Solid.FromPolygons(newpolygons); result.Properties = Properties.Merge(csg.Properties); result.IsCanonicalized = IsCanonicalized && csg.IsCanonicalized; result.IsRetesselated = IsRetesselated && csg.IsRetesselated; return(result); }
public Solid GetCsg(Solid sourcecsg) { var newpolygons = new List <Polygon>(); foreach (var polygon in sourcecsg.Polygons) { var newpolygon = GetPolygon(polygon); if (newpolygon.Vertices.Count >= 3) { newpolygons.Add(newpolygon); } } return(Solid.FromPolygons(newpolygons)); }
public Solid Transform(Matrix4x4 matrix4x4) { var ismirror = matrix4x4.IsMirroring; var transformedvertices = new Dictionary <int, Vertex>(); var transformedplanes = new Dictionary <int, Plane>(); var newpolygons = new List <Polygon>(); foreach (var p in Polygons) { Plane newplane; var plane = p.Plane; var planetag = plane.Tag; if (transformedplanes.ContainsKey(planetag)) { newplane = transformedplanes[planetag]; } else { newplane = plane.Transform(matrix4x4); transformedplanes[planetag] = newplane; } var newvertices = new List <Vertex>(); foreach (var v in p.Vertices) { Vertex newvertex; var vertextag = v.Tag; if (transformedvertices.ContainsKey(vertextag)) { newvertex = transformedvertices[vertextag]; } else { newvertex = v.Transform(matrix4x4); transformedvertices[vertextag] = newvertex; } newvertices.Add(newvertex); } if (ismirror) { newvertices.Reverse(); } newpolygons.Add(new Polygon(newvertices, p.Shared, newplane)); } var result = Solid.FromPolygons(newpolygons); result.Properties = this.Properties.Transform(matrix4x4); result.IsRetesselated = this.IsRetesselated; result.IsCanonicalized = this.IsCanonicalized; return(result); }
Solid SubtractSub(Solid csg, bool retesselate, bool canonicalize) { var a = new Tree(Bounds, Polygons); var b = new Tree(csg.Bounds, csg.Polygons); a.Invert(); a.ClipTo(b); b.ClipTo(a, true); a.AddPolygons(b.AllPolygons()); a.Invert(); var result = Solid.FromPolygons(a.AllPolygons()); if (retesselate) { result = result.Retesselated(); } if (canonicalize) { result = result.Canonicalized(); } return(result); }
public static Solid Sphere(SphereOptions options) { var center = options.Center; var radius = Math.Abs(options.Radius); if (radius == 0.0) { return(new Solid()); } var resolution = options.Resolution; var xvector = options.XAxis * radius; var yvector = options.YAxis * radius; var zvector = options.ZAxis * radius; if (resolution < 4) { resolution = 4; } var qresolution = resolution / 4; var prevcylinderpoint = new Vector3D(0, 0, 0); var polygons = new List <Polygon>(); for (var slice1 = 0; slice1 <= resolution; slice1++) { var angle = Math.PI * 2.0 * slice1 / resolution; var cylinderpoint = xvector * (Math.Cos(angle)) + (yvector * (Math.Sin(angle))); if (slice1 > 0) { double prevcospitch = 0, prevsinpitch = 0; for (var slice2 = 0; slice2 <= qresolution; slice2++) { var pitch = 0.5 * Math.PI * (double)slice2 / qresolution; var cospitch = Math.Cos(pitch); var sinpitch = Math.Sin(pitch); if (slice2 > 0) { var vertices = new List <Vertex>(); vertices.Add(new Vertex(center + (prevcylinderpoint * (prevcospitch) - (zvector * (prevsinpitch))))); vertices.Add(new Vertex(center + (cylinderpoint * (prevcospitch) - (zvector * (prevsinpitch))))); if (slice2 < qresolution) { vertices.Add(new Vertex(center + (cylinderpoint * (cospitch) - (zvector * (sinpitch))))); } vertices.Add(new Vertex(center + (prevcylinderpoint * (cospitch) - (zvector * (sinpitch))))); polygons.Add(new Polygon(vertices)); vertices = new List <Vertex>(); vertices.Add(new Vertex(center + (prevcylinderpoint * (prevcospitch) + (zvector * (prevsinpitch))))); vertices.Add(new Vertex(center + (cylinderpoint * (prevcospitch) + (zvector * (prevsinpitch))))); if (slice2 < qresolution) { vertices.Add(new Vertex(center + (cylinderpoint * (cospitch) + (zvector * (sinpitch))))); } vertices.Add(new Vertex(center + (prevcylinderpoint * (cospitch) + (zvector * (sinpitch))))); vertices.Reverse(); polygons.Add(new Polygon(vertices)); } prevcospitch = cospitch; prevsinpitch = sinpitch; } } prevcylinderpoint = cylinderpoint; } var result = Solid.FromPolygons(polygons); return(result); }
public static Solid Cylinder(CylinderOptions options) { var s = options.Start; var e = options.End; var r = Math.Abs(options.RadiusStart); var rEnd = Math.Abs(options.RadiusEnd); var rStart = r; var alpha = options.SectorAngle; alpha = alpha > 360 ? alpha % 360 : alpha; if ((rEnd == 0) && (rStart == 0)) { return(new Solid()); } if (s.Equals(e)) { return(new Solid()); } var slices = options.Resolution; var ray = e - (s); var axisZ = ray.Unit; var axisX = axisZ.RandomNonParallelVector().Unit; var axisY = axisX.Cross(axisZ).Unit; axisX = axisZ.Cross(axisY).Unit; var start = new Vertex(s); var end = new Vertex(e); var polygons = new List <Polygon>(); Func <double, double, double, Vertex> point = (stack, slice, radius) => { var angle = slice * Math.PI * alpha / 180; var outp = axisX * (Math.Cos(angle)) + (axisY * (Math.Sin(angle))); var pos = s + (ray * (stack)) + (outp * (radius)); return(new Vertex(pos)); }; if (alpha > 0) { for (var i = 0; i < slices; i++) { double t0 = (double)i / slices; double t1 = (double)(i + 1) / slices; if (rEnd == rStart) { polygons.Add(new Polygon(start, point(0, t0, rEnd), point(0, t1, rEnd))); polygons.Add(new Polygon(point(0, t1, rEnd), point(0, t0, rEnd), point(1, t0, rEnd), point(1, t1, rEnd))); polygons.Add(new Polygon(end, point(1, t1, rEnd), point(1, t0, rEnd))); } else { if (rStart > 0) { polygons.Add(new Polygon(start, point(0, t0, rStart), point(0, t1, rStart))); polygons.Add(new Polygon(point(0, t0, rStart), point(1, t0, rEnd), point(0, t1, rStart))); } if (rEnd > 0) { polygons.Add(new Polygon(end, point(1, t1, rEnd), point(1, t0, rEnd))); polygons.Add(new Polygon(point(1, t0, rEnd), point(1, t1, rEnd), point(0, t1, rStart))); } } } if (alpha < 360) { polygons.Add(new Polygon(start, end, point(0, 0, rStart))); polygons.Add(new Polygon(point(0, 0, rStart), end, point(1, 0, rEnd))); polygons.Add(new Polygon(start, point(0, 1, rStart), end)); polygons.Add(new Polygon(point(0, 1, rStart), point(1, 1, rEnd), end)); } } var result = Solid.FromPolygons(polygons); return(result); }