public void MirrorTests() { { Box leftBox = new Box(10, 20, 30, "leftBox", createCentered: false); CsgObject rightBox = new Box(11, 21, 31, "rightBox", createCentered: false); rightBox = new Align(rightBox, Face.Left, leftBox, Face.Right); CsgObject union = new Union(leftBox, rightBox); Assert.IsTrue(union.XSize == 21, "Correct XSize"); AxisAlignedBoundingBox unionBounds = union.GetAxisAlignedBoundingBox(); Assert.IsTrue(unionBounds.minXYZ == new Vector3(), "MinXYZ at 0"); Assert.IsTrue(union.GetAxisAlignedBoundingBox().maxXYZ == new Vector3(21, 21, 31), "MaxXYZ correct"); } { Box leftBox = new Box(10, 20, 30, "leftBox", createCentered: false); CsgObject rightBox = leftBox.NewMirrorAccrossX(name: "rightBox"); rightBox = new Align(rightBox, Face.Left, leftBox, Face.Right); CsgObject union = new Union(leftBox, rightBox); Assert.IsTrue(union.XSize == 20, "Correct XSize"); AxisAlignedBoundingBox unionBounds = union.GetAxisAlignedBoundingBox(); Assert.IsTrue(unionBounds.minXYZ == new Vector3(), "MinXYZ at 0"); Assert.IsTrue(union.GetAxisAlignedBoundingBox().maxXYZ == new Vector3(20, 20, 30), "MaxXYZ correct"); } { Box frontBox = new Box(10, 20, 30, createCentered: false); CsgObject backBox = frontBox.NewMirrorAccrossY(); backBox = new Align(backBox, Face.Front, frontBox, Face.Back); CsgObject union = new Union(frontBox, backBox); Assert.IsTrue(union.YSize == 40, "Correct YSize"); AxisAlignedBoundingBox unionBounds = union.GetAxisAlignedBoundingBox(); Assert.IsTrue(unionBounds.minXYZ == new Vector3(), "MinXYZ at 0"); Assert.IsTrue(union.GetAxisAlignedBoundingBox().maxXYZ == new Vector3(10, 40, 30), "MaxXYZ correct"); } }
public static CsgObject CreateNegativeBevel(double innerRadius, double outerRadius, double height, Alignment alignment = Alignment.z, double extraDimension = defaultExtraRadialDimension, string name = "") { double width = outerRadius - innerRadius; List<Vector2> points = new List<Vector2>(); int numCurvePoints = 6; for (int curvePoint = 0; curvePoint <= numCurvePoints; curvePoint++) { double x = width - Math.Cos((MathHelper.Tau / 4 * curvePoint / numCurvePoints)) * width; double y = height - Math.Sin((MathHelper.Tau / 4 * curvePoint / numCurvePoints)) * height; points.Add(new Vector2(x, y)); } points.Add(new Vector2(width, 0)); points.Add(new Vector2(width, height)); CsgObject bevel = new RotateExtrude(points.ToArray(), innerRadius, alignment, name); points.Clear(); points.Add(new Vector2(0, -extraDimension)); points.Add(new Vector2(width + extraDimension, -extraDimension)); points.Add(new Vector2(width + extraDimension, height + extraDimension)); points.Add(new Vector2(0, height + extraDimension)); CsgObject cut = new RotateExtrude(points.ToArray(), innerRadius, alignment, name); cut = new Align(cut, Face.Bottom, bevel, Face.Bottom, 0, 0, .1); //return cut; bevel = cut - bevel; return bevel; }
public static CsgObject CreateFillet(CsgObject objectA, Face faceA, CsgObject objectB, Face faceB, double radius, double extraDimension = defaultExtraDimension) { int centralAxis = 0; // we start defaulted to x switch ((Edge)(faceA | faceB)) { case Edge.LeftTop: case Edge.LeftBottom: case Edge.RightTop: case Edge.RightBottom: centralAxis = 1; // y axis break; case Edge.LeftFront: case Edge.LeftBack: case Edge.RightFront: case Edge.RightBack: centralAxis = 2; // z axis break; } AxisAlignedBoundingBox boundsA = objectA.GetAxisAlignedBoundingBox(); AxisAlignedBoundingBox boundsB = objectB.GetAxisAlignedBoundingBox(); double maxMin = Math.Max(boundsA.minXYZ[centralAxis], boundsB.minXYZ[centralAxis]); double minMax = Math.Min(boundsA.maxXYZ[centralAxis], boundsB.maxXYZ[centralAxis]); if (maxMin >= minMax) { throw new ArgumentException("Your two objects must overlap to have a fillet be created."); } Vector3 size = new Vector3(radius, radius, radius); size[centralAxis] = minMax - maxMin; Round newFilletRound = new Round(size); Face faceToGetBevelFor = CsgObject.GetOposite(faceA) | CsgObject.GetOposite(faceB); newFilletRound.RoundEdge((Edge)faceToGetBevelFor, radius, extraDimension); CsgObject newFillet = new SetCenter(newFilletRound, objectA.GetCenter()); newFillet = new Align(newFillet, CsgObject.GetOposite(faceA), objectA, faceA); newFillet = new Align(newFillet, CsgObject.GetOposite(faceB), objectB, faceB); return newFillet; }
public void RoundPoint(Face threeFacesThatSharePoint, double radius, double extraDimension = defaultExtraDimension) { if (roundedPoints.ContainsKey(threeFacesThatSharePoint)) { return; } double radiusBoxSize = radius + extraDimension; switch (threeFacesThatSharePoint) { case Face.Left | Face.Front | Face.Bottom: { RoundEdge(Edge.LeftFront, radius, extraDimension); RoundEdge(Edge.LeftBottom, radius, extraDimension); RoundEdge(Edge.FrontBottom, radius, extraDimension); CsgObject pointRound = new Box(radiusBoxSize, radiusBoxSize, radiusBoxSize, "box"); CsgObject pointCut = new Sphere(radius, "sphere"); pointCut = new Align(pointCut, threeFacesThatSharePoint, pointRound, threeFacesThatSharePoint, extraDimension, extraDimension, extraDimension); pointRound -= pointCut; pointRound = new Align(pointRound, threeFacesThatSharePoint, GetEdgeOffset(threeFacesThatSharePoint), -extraDimension, -extraDimension, -extraDimension); root += pointRound; } break; case Face.Left | Face.Front | Face.Top: { RoundEdge(Edge.LeftFront, radius, extraDimension); RoundEdge(Edge.LeftTop, radius, extraDimension); RoundEdge(Edge.FrontTop, radius, extraDimension); CsgObject pointRound = new Box(radiusBoxSize, radiusBoxSize, radiusBoxSize, "box"); CsgObject pointCut = new Sphere(radius, "sphere"); pointCut = new Align(pointCut, threeFacesThatSharePoint, pointRound, threeFacesThatSharePoint, extraDimension, extraDimension, -extraDimension); pointRound -= pointCut; pointRound = new Align(pointRound, threeFacesThatSharePoint, GetEdgeOffset(threeFacesThatSharePoint), -extraDimension, -extraDimension, extraDimension); root += pointRound; } break; case Face.Left | Face.Back | Face.Bottom: { RoundEdge(Edge.LeftBack, radius, extraDimension); RoundEdge(Edge.LeftBottom, radius, extraDimension); RoundEdge(Edge.BackBottom, radius, extraDimension); CsgObject pointRound = new Box(radiusBoxSize, radiusBoxSize, radiusBoxSize, "box"); CsgObject pointCut = new Sphere(radius, "sphere"); pointCut = new Align(pointCut, threeFacesThatSharePoint, pointRound, threeFacesThatSharePoint, extraDimension, -extraDimension, extraDimension); pointRound -= pointCut; pointRound = new Align(pointRound, threeFacesThatSharePoint, GetEdgeOffset(threeFacesThatSharePoint), -extraDimension, extraDimension, -extraDimension); root += pointRound; } break; case Face.Left | Face.Back | Face.Top: { RoundEdge(Edge.LeftBack, radius, extraDimension); RoundEdge(Edge.LeftTop, radius, extraDimension); RoundEdge(Edge.BackTop, radius, extraDimension); CsgObject pointRound = new Box(radiusBoxSize, radiusBoxSize, radiusBoxSize, "box"); CsgObject pointCut = new Sphere(radius, "sphere"); pointCut = new Align(pointCut, threeFacesThatSharePoint, pointRound, threeFacesThatSharePoint, extraDimension, -extraDimension, -extraDimension); pointRound -= pointCut; pointRound = new Align(pointRound, threeFacesThatSharePoint, GetEdgeOffset(threeFacesThatSharePoint), -extraDimension, extraDimension, extraDimension); root += pointRound; } break; case Face.Right | Face.Front | Face.Bottom: { RoundEdge(Edge.RightFront, radius, extraDimension); RoundEdge(Edge.RightBottom, radius, extraDimension); RoundEdge(Edge.FrontBottom, radius, extraDimension); CsgObject pointRound = new Box(radiusBoxSize, radiusBoxSize, radiusBoxSize, "box"); CsgObject pointCut = new Sphere(radius, "sphere"); pointCut = new Align(pointCut, threeFacesThatSharePoint, pointRound, threeFacesThatSharePoint, -extraDimension, extraDimension, extraDimension); pointRound -= pointCut; pointRound = new Align(pointRound, threeFacesThatSharePoint, GetEdgeOffset(threeFacesThatSharePoint), extraDimension, -extraDimension, -extraDimension); root += pointRound; } break; case Face.Right | Face.Front | Face.Top: { RoundEdge(Edge.RightFront, radius, extraDimension); RoundEdge(Edge.RightTop, radius, extraDimension); RoundEdge(Edge.FrontTop, radius, extraDimension); CsgObject pointRound = new Box(radiusBoxSize, radiusBoxSize, radiusBoxSize, "box"); CsgObject pointCut = new Sphere(radius, "sphere"); pointCut = new Align(pointCut, threeFacesThatSharePoint, pointRound, threeFacesThatSharePoint, -extraDimension, extraDimension, -extraDimension); pointRound -= pointCut; pointRound = new Align(pointRound, threeFacesThatSharePoint, GetEdgeOffset(threeFacesThatSharePoint), extraDimension, -extraDimension, extraDimension); root += pointRound; } break; case Face.Right | Face.Back | Face.Bottom: { RoundEdge(Edge.RightBack, radius, extraDimension); RoundEdge(Edge.RightBottom, radius, extraDimension); RoundEdge(Edge.BackBottom, radius, extraDimension); CsgObject pointRound = new Box(radiusBoxSize, radiusBoxSize, radiusBoxSize, "box"); CsgObject pointCut = new Sphere(radius, "sphere"); pointCut = new Align(pointCut, threeFacesThatSharePoint, pointRound, threeFacesThatSharePoint, -extraDimension, -extraDimension, extraDimension); pointRound -= pointCut; pointRound = new Align(pointRound, threeFacesThatSharePoint, GetEdgeOffset(threeFacesThatSharePoint), extraDimension, extraDimension, -extraDimension); root += pointRound; } break; case Face.Right | Face.Back | Face.Top: { RoundEdge(Edge.RightBack, radius, extraDimension); RoundEdge(Edge.RightTop, radius, extraDimension); RoundEdge(Edge.BackTop, radius, extraDimension); CsgObject pointRound = new Box(radiusBoxSize, radiusBoxSize, radiusBoxSize, "box"); CsgObject pointCut = new Sphere(radius, "sphere"); pointCut = new Align(pointCut, threeFacesThatSharePoint, pointRound, threeFacesThatSharePoint, -extraDimension, -extraDimension, -extraDimension); pointRound -= pointCut; pointRound = new Align(pointRound, threeFacesThatSharePoint, GetEdgeOffset(threeFacesThatSharePoint), extraDimension, extraDimension, extraDimension); root += pointRound; } break; default: throw new NotImplementedException("Don't know how to round " + threeFacesThatSharePoint.ToString()); } if (!roundedPoints.ContainsKey(threeFacesThatSharePoint)) { roundedPoints.Add(threeFacesThatSharePoint, radius); } }
public void RoundEdge(Edge edgeToRound, double radius, double extraDimension = defaultExtraDimension) { if (roundedEdges.ContainsKey(edgeToRound)) { return; } CsgObject newRound = null; double radiusBoxSize = radius + extraDimension; switch (edgeToRound) { case Edge.LeftFront: { double zSize = size.z + 2 * extraDimension; newRound = new Box(radiusBoxSize, radiusBoxSize, zSize); CsgObject frontTopCut = new Cylinder(radius, zSize + extraDimension * 2, Alignment.z); frontTopCut = new Align(frontTopCut, Face.Left | Face.Front, newRound, Face.Left | Face.Front, extraDimension, extraDimension, 0); newRound -= frontTopCut; newRound = new Align(newRound, Face.Left | Face.Front, GetEdgeOffset(Face.Left | Face.Front), -extraDimension, -extraDimension, 0); } break; case Edge.LeftBack: { double zSize = size.z + 2 * extraDimension; newRound = new Box(radiusBoxSize, radiusBoxSize, zSize); CsgObject BackTopCut = new Cylinder(radius, zSize + extraDimension * 2, Alignment.z); BackTopCut = new Align(BackTopCut, Face.Left | Face.Back, newRound, Face.Left | Face.Back, extraDimension, -extraDimension, 0); newRound -= BackTopCut; newRound = new Align(newRound, Face.Left | Face.Back, GetEdgeOffset(Face.Left | Face.Back), -extraDimension, extraDimension, 0); } break; case Edge.LeftTop: { double ySize = size.y + 2 * extraDimension; newRound = new Box(radiusBoxSize, ySize, radiusBoxSize); CsgObject frontTopCut = new Cylinder(radius, ySize + extraDimension * 2, Alignment.y); frontTopCut = new Align(frontTopCut, Face.Left | Face.Top, newRound, Face.Left | Face.Top, extraDimension, 0, -extraDimension); newRound -= frontTopCut; newRound = new Align(newRound, Face.Left | Face.Top, GetEdgeOffset(Face.Left | Face.Top), -extraDimension, 0, extraDimension); } break; case Edge.LeftBottom: { double ySize = size.y + 2 * extraDimension; newRound = new Box(radiusBoxSize, ySize, radiusBoxSize); CsgObject frontTopCut = new Cylinder(radius, ySize + extraDimension * 2, Alignment.y); frontTopCut = new Align(frontTopCut, Face.Left | Face.Bottom, newRound, Face.Left | Face.Bottom, extraDimension, 0, extraDimension); newRound -= frontTopCut; newRound = new Align(newRound, Face.Left | Face.Bottom, GetEdgeOffset(Face.Left | Face.Bottom), -extraDimension, 0, -extraDimension); } break; case Edge.RightFront: { double zSize = size.z + 2 * extraDimension; newRound = new Box(radiusBoxSize, radiusBoxSize, zSize); CsgObject frontTopCut = new Cylinder(radius, zSize + extraDimension * 2, Alignment.z); frontTopCut = new Align(frontTopCut, Face.Right | Face.Front, newRound, Face.Right | Face.Front, -extraDimension, extraDimension, 0); newRound -= frontTopCut; newRound = new Align(newRound, Face.Right | Face.Front, GetEdgeOffset(Face.Right | Face.Front), extraDimension, -extraDimension, 0); } break; case Edge.RightTop: { double ySize = size.y + 2 * extraDimension; newRound = new Box(radiusBoxSize, ySize, radiusBoxSize); CsgObject frontTopCut = new Cylinder(radius, ySize + extraDimension * 2, Alignment.y); frontTopCut = new Align(frontTopCut, Face.Right | Face.Top, newRound, Face.Right | Face.Top, -extraDimension, 0, -extraDimension); newRound -= frontTopCut; newRound = new Align(newRound, Face.Right | Face.Top, GetEdgeOffset(Face.Right | Face.Top), extraDimension, 0, extraDimension); } break; case Edge.RightBottom: { double ySize = size.y + 2 * extraDimension; newRound = new Box(radiusBoxSize, ySize, radiusBoxSize); CsgObject frontBottomCut = new Cylinder(radius, ySize + extraDimension * 2, Alignment.y); frontBottomCut = new Align(frontBottomCut, Face.Right | Face.Bottom, newRound, Face.Right | Face.Bottom, -extraDimension, 0, extraDimension); newRound -= frontBottomCut; newRound = new Align(newRound, Face.Right | Face.Bottom, GetEdgeOffset(Face.Right | Face.Bottom), extraDimension, 0, -extraDimension); } break; case Edge.RightBack: { double zSize = size.z + 2 * extraDimension; newRound = new Box(radiusBoxSize, radiusBoxSize, zSize); CsgObject BackTopCut = new Cylinder(radius, zSize + extraDimension * 2, Alignment.z); BackTopCut = new Align(BackTopCut, Face.Right | Face.Back, newRound, Face.Right | Face.Back, -extraDimension, -extraDimension, 0); newRound -= BackTopCut; newRound = new Align(newRound, Face.Right | Face.Back, GetEdgeOffset(Face.Right | Face.Back), extraDimension, extraDimension, 0); } break; case Edge.FrontTop: { double xSize = size.x + 2 * extraDimension; newRound = new Box(xSize, radiusBoxSize, radiusBoxSize); CsgObject frontTopCut = new Cylinder(radius, xSize + extraDimension * 2, Alignment.x); frontTopCut = new Align(frontTopCut, Face.Front | Face.Top, newRound, Face.Front | Face.Top, 0, extraDimension, -extraDimension); newRound -= frontTopCut; newRound = new Align(newRound, Face.Front | Face.Top, GetEdgeOffset(Face.Front | Face.Top), 0, -extraDimension, extraDimension); } break; case Edge.FrontBottom: { double xSize = size.x + 2 * extraDimension; newRound = new Box(xSize, radiusBoxSize, radiusBoxSize); CsgObject frontTopCut = new Cylinder(radius, xSize + extraDimension * 2, Alignment.x); frontTopCut = new Align(frontTopCut, Face.Front | Face.Bottom, newRound, Face.Front | Face.Bottom, 0, extraDimension, extraDimension); newRound -= frontTopCut; newRound = new Align(newRound, Face.Front | Face.Bottom, GetEdgeOffset(Face.Front | Face.Bottom), 0, -extraDimension, -extraDimension); } break; case Edge.BackBottom: { double xSize = size.x + 2 * extraDimension; newRound = new Box(xSize, radiusBoxSize, radiusBoxSize); CsgObject backBottomCut = new Cylinder(radius, xSize + extraDimension * 2, Alignment.x); backBottomCut = new Align(backBottomCut, Face.Back | Face.Bottom, newRound, Face.Back | Face.Bottom, 0, -extraDimension, extraDimension); newRound -= backBottomCut; newRound = new Align(newRound, Face.Back | Face.Bottom, GetEdgeOffset(Face.Back | Face.Bottom), 0, extraDimension, -extraDimension); } break; case Edge.BackTop: { double xSize = size.x + 2 * extraDimension; newRound = new Box(xSize, radiusBoxSize, radiusBoxSize); CsgObject backTopCut = new Cylinder(radius, xSize + extraDimension * 2, Alignment.x); backTopCut = new Align(backTopCut, Face.Back | Face.Top, newRound, Face.Back | Face.Top, 0, -extraDimension, -extraDimension); newRound -= backTopCut; newRound = new Align(newRound, Face.Back | Face.Top, GetEdgeOffset(Face.Back | Face.Top), 0, extraDimension, extraDimension); } break; default: throw new NotImplementedException("Don't know how to round " + edgeToRound.ToString()); } if (root is Box) { root = newRound; } else { root += newRound; } roundedEdges.Add(edgeToRound, radius); CheckCornersAndRoundIfNeeded(extraDimension); }
public void BevelAll(double radius) { Round roundToApply = new Round(Size); roundToApply.RoundAll(radius); CsgObject offsetRoundToApply = new Align(roundToApply, Face.Left | Face.Front | Face.Bottom, root, Face.Left | Face.Front | Face.Bottom); root -= offsetRoundToApply; }
public void BevelEdge(Edge edgeToBevel, double radius) { Round roundToApply = new Round(Size); roundToApply.RoundEdge(edgeToBevel, radius); CsgObject offsetRoundToApply = new Align(roundToApply, Face.Left | Face.Front | Face.Bottom, root, Face.Left | Face.Front | Face.Bottom); root -= offsetRoundToApply; }
/// <summary> /// Bevel a give edge. The edge is chosen by saying which 2 faces are to be used, /// and or-ing them together /// </summary> /// <param name="facesThatShareEdge">The two faces or-ed together with |</param> /// <param name="radius">The radius of the bevel</param> public void BevelEdge(Face facesThatShareEdge, double radius) { Round roundToApply = new Round(Size); roundToApply.RoundEdge((Edge)facesThatShareEdge, radius); CsgObject offsetRoundToApply = new Align(roundToApply, Face.Left | Face.Front | Face.Bottom, root, Face.Left | Face.Front | Face.Bottom); root -= offsetRoundToApply; }