Solid IntersectSub(Solid csg, bool retesselate, bool canonicalize) { Tree a = new Tree(Polygons); Tree b = new Tree(csg.Polygons); a.Invert(); b.ClipTo(a); b.Invert(); a.ClipTo(b); b.ClipTo(a); a.AddPolygons(b.AllPolygons()); a.Invert(); Solid result = Solid.FromPolygons(a.AllPolygons()); if (retesselate) { result = result.Retesselated(); } if (canonicalize) { result = result.Canonicalized(); } return(result); }
Solid UnionSub(Solid csg, bool retesselate, bool canonicalize) { if (!MayOverlap(csg)) { return(UnionForNonIntersecting(csg)); } else { Tree a = new Tree(Polygons); Tree b = new Tree(csg.Polygons); a.ClipTo(b, false); b.ClipTo(a); b.Invert(); b.ClipTo(a); b.Invert(); Polygon[] ArrayPolygonA = a.AllPolygons().ToArray(); Polygon[] ArrayPolygonB = b.AllPolygons().ToArray(); Polygon[] ArrayNewPolygon = new Polygon[ArrayPolygonA.Length + ArrayPolygonB.Length]; Array.Copy(ArrayPolygonA, 0, ArrayNewPolygon, 0, ArrayPolygonA.Length); Array.Copy(ArrayPolygonB, 0, ArrayNewPolygon, ArrayPolygonA.Length, ArrayPolygonB.Length); Solid result = Solid.FromPolygons(ArrayNewPolygon.ToList()); 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 Vector3(info[1]); //var plane = new Plane(normal, 1); IEnumerable <Vertex> vertices = info[0].Select(i => { var pos = new Vector3( 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(NoTexVertex(pos)); }); return(new Polygon(options.SolidColor, vertices.ToArray())); }).ToList()); return(result); }
public Solid GetCsg(Solid sourcecsg) { List <Polygon> newpolygons = new List <Polygon>(); foreach (Polygon polygon in sourcecsg.Polygons) { Polygon newpolygon = GetPolygon(polygon); if (newpolygon.Vertices.Length >= 3) { newpolygons.Add(newpolygon); } } return(Solid.FromPolygons(newpolygons)); }
Solid UnionForNonIntersecting(Solid csg) { Polygon[] ArrayPolygonA = Polygons.ToArray(); Polygon[] ArrayPolygonB = csg.Polygons.ToArray(); Polygon[] ArrayNewPolygon = new Polygon[ArrayPolygonA.Length + ArrayPolygonB.Length]; Array.Copy(ArrayPolygonA, 0, ArrayNewPolygon, 0, ArrayPolygonA.Length); Array.Copy(ArrayPolygonB, 0, ArrayNewPolygon, ArrayPolygonA.Length, ArrayPolygonB.Length); Solid result = Solid.FromPolygons(ArrayNewPolygon.ToList()); result.IsCanonicalized = IsCanonicalized && csg.IsCanonicalized; result.IsRetesselated = IsRetesselated && csg.IsRetesselated; return(result); }
public Solid Retesselated() { if (IsRetesselated) { return(this); } else { Solid csg = this; Dictionary <Plane, List <Polygon> > polygonsPerPlane = new Dictionary <Plane, List <Polygon> >(); foreach (Polygon polygon in csg.Polygons) { Plane plane = polygon.Plane; List <Polygon> ppp; if (polygonsPerPlane.TryGetValue(plane, out ppp)) { ppp.Add(polygon); } else { ppp = new List <Polygon>(1); ppp.Add(polygon); polygonsPerPlane.Add(plane, ppp); } } var destpolygons = new List <Polygon>(); foreach (KeyValuePair <Plane, List <Polygon> > planetag in polygonsPerPlane) { var sourcepolygons = planetag.Value; if (sourcepolygons.Count < 2) { destpolygons.AddRange(sourcepolygons); } else { List <Polygon> retesselatedpolygons = new List <Polygon>(sourcepolygons.Count); Solid.RetesselateCoplanarPolygons(sourcepolygons, retesselatedpolygons); destpolygons.AddRange(retesselatedpolygons); } } Solid result = Solid.FromPolygons(destpolygons); result.IsRetesselated = true; return(result); } }
public Solid Transform(Matrix matrix4x4) { Dictionary <Vertex, Vertex> transformedvertices = new Dictionary <Vertex, Vertex>(); Dictionary <Plane, Plane> transformedplanes = new Dictionary <Plane, Plane>(); Polygon[] ArrayNewPolygon = new Polygon[Polygons.Count]; for (int i = 0; i < Polygons.Count; i++) { Polygon ActivePolygon = Polygons[i]; Plane newplane; Plane plane = ActivePolygon.Plane; if (transformedplanes.ContainsKey(plane)) { newplane = transformedplanes[plane]; } else { newplane = plane.Project(matrix4x4); transformedplanes[plane] = newplane; } Vertex[] ArrayNewVertex = new Vertex[ActivePolygon.Vertices.Length]; for (int V = 0; V < ActivePolygon.Vertices.Length; ++V) { Vertex ActiveVertex = ActivePolygon.Vertices[V]; Vertex newvertex; if (transformedvertices.ContainsKey(ActiveVertex)) { newvertex = transformedvertices[ActiveVertex]; } else { newvertex = ActiveVertex.Transform(matrix4x4); transformedvertices[ActiveVertex] = newvertex; } ArrayNewVertex[V] = newvertex; } ArrayNewPolygon[i] = new Polygon(ActivePolygon.PolygonColor, ArrayNewVertex, newplane); } Solid result = Solid.FromPolygons(ArrayNewPolygon.ToList()); result.IsRetesselated = this.IsRetesselated; result.IsCanonicalized = this.IsCanonicalized; return(result); }
public static Solid Sphere(SphereOptions options) { var center = options.Center; float 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 Vector3(0, 0, 0); var polygons = new List <Polygon>(); for (var slice1 = 0; slice1 <= resolution; slice1++) { float angle = (float)Math.PI * 2.0f * slice1 / resolution; Vector3 cylinderpoint = xvector * ((float)Math.Cos(angle)) + (yvector * ((float)Math.Sin(angle))); if (slice1 > 0) { float prevcospitch = 0, prevsinpitch = 0; for (var slice2 = 0; slice2 <= qresolution; slice2++) { float pitch = 0.5f * (float)Math.PI * slice2 / qresolution; float cospitch = (float)Math.Cos(pitch); float sinpitch = (float)Math.Sin(pitch); if (slice2 > 0) { List <Vertex> vertices = new List <Vertex>(); vertices.Add(NoTexVertex(center + (prevcylinderpoint * (prevcospitch) - (zvector * (prevsinpitch))))); vertices.Add(NoTexVertex(center + (cylinderpoint * (prevcospitch) - (zvector * (prevsinpitch))))); if (slice2 < qresolution) { vertices.Add(NoTexVertex(center + (cylinderpoint * (cospitch) - (zvector * (sinpitch))))); } vertices.Add(NoTexVertex(center + (prevcylinderpoint * (cospitch) - (zvector * (sinpitch))))); polygons.Add(new Polygon(options.SolidColor, vertices.ToArray())); vertices = new List <Vertex>(); vertices.Add(NoTexVertex(center + (prevcylinderpoint * (prevcospitch) + (zvector * (prevsinpitch))))); vertices.Add(NoTexVertex(center + (cylinderpoint * (prevcospitch) + (zvector * (prevsinpitch))))); if (slice2 < qresolution) { vertices.Add(NoTexVertex(center + (cylinderpoint * (cospitch) + (zvector * (sinpitch))))); } vertices.Add(NoTexVertex(center + (prevcylinderpoint * (cospitch) + (zvector * (sinpitch))))); vertices.Reverse(); polygons.Add(new Polygon(options.SolidColor, vertices.ToArray())); } 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); Vector3 axisZ = ray.Unit(); Vector3 axisX = axisZ.RandomNonParallelVector().Unit(); Vector3 axisY = axisX.Cross(axisZ).Unit(); axisX = axisZ.Cross(axisY).Unit(); var start = NoTexVertex(s); var end = NoTexVertex(e); var polygons = new List <Polygon>(); Func <float, float, float, Vertex> point = (stack, slice, radius) => { var angle = slice * Math.PI * alpha / 180; Vector3 outp = axisX * ((float)Math.Cos(angle)) + (axisY * ((float)Math.Sin(angle))); var pos = s + (ray * (stack)) + (outp * (radius)); return(NoTexVertex(pos)); }; if (alpha > 0) { for (var i = 0; i < slices; i++) { float t0 = (float)i / slices; float t1 = (float)(i + 1) / slices; if (rEnd == rStart) { polygons.Add(new Polygon(options.SolidColor, start, point(0, t0, rEnd), point(0, t1, rEnd))); polygons.Add(new Polygon(options.SolidColor, point(0, t1, rEnd), point(0, t0, rEnd), point(1, t0, rEnd), point(1, t1, rEnd))); polygons.Add(new Polygon(options.SolidColor, end, point(1, t1, rEnd), point(1, t0, rEnd))); } else { if (rStart > 0) { polygons.Add(new Polygon(options.SolidColor, start, point(0, t0, rStart), point(0, t1, rStart))); polygons.Add(new Polygon(options.SolidColor, point(0, t0, rStart), point(1, t0, rEnd), point(0, t1, rStart))); } if (rEnd > 0) { polygons.Add(new Polygon(options.SolidColor, end, point(1, t1, rEnd), point(1, t0, rEnd))); polygons.Add(new Polygon(options.SolidColor, point(1, t0, rEnd), point(1, t1, rEnd), point(0, t1, rStart))); } } } if (alpha < 360) { polygons.Add(new Polygon(options.SolidColor, start, end, point(0, 0, rStart))); polygons.Add(new Polygon(options.SolidColor, point(0, 0, rStart), end, point(1, 0, rEnd))); polygons.Add(new Polygon(options.SolidColor, start, point(0, 1, rStart), end)); polygons.Add(new Polygon(options.SolidColor, point(0, 1, rStart), point(1, 1, rEnd), end)); } } var result = Solid.FromPolygons(polygons); return(result); }