public void If_the_ray_does_not_point_at_the_AABB_the_result_is_false_and_the_distance_is_set_to_infinity() { var box = new AxisAlignedBoundingBox(new Point(1, 1, 1), new Point(2, 2, 2)); var ray = new Ray(new Point(0.5, -1, 2), -Vector.UnitY); Assert.False(box.IntersectsRay(ray, 0, double.PositiveInfinity)); }
public void If_the_ray_points_at_the_AABB_the_result_is_true_and_the_distance_is_set_correctly() { var box = new AxisAlignedBoundingBox(new Point(0, 0, 0), new Point(2, 2, 2)); var ray = new Ray(new Point(-1, 1, 1), new Vector(1, 0.1, 0.2).ToUnitVector()); Assert.True(box.IntersectsRay(ray, 0, double.PositiveInfinity)); }
public BvhNode(IIntersectable left, IIntersectable right) { _left = left; _right = right; if (left != null) { _leftBounds = left.GetBoundingBox(); } if (right != null) { _rightBounds = right.GetBoundingBox(); } }
/// <summary> /// TODO: This method is BUTT SLOW. For now it just loops over all of the triangles in the mesh and returns the closest intersection... /// </summary> public Intersection FindClosestIntersectionWith(Ray ray) { if (_boundingBox == null) { _boundingBox = GetBoundingBox(); } if (!_boundingBox.IntersectsRay(ray, 0, double.PositiveInfinity)) { return null; } return Triangles .Select(triangle => triangle.FindClosestIntersectionWith(ray)) .WhereNotNull() .OrderBy(intersection => intersection.Distance) .FirstOrDefault(); }
public void For_ray_directions_with_zeros_the_result_is_still_true_for_valid_intersections() { var box = new AxisAlignedBoundingBox(new Point(0, 0, 0), new Point(2, 2, 2)); var ray = new Ray(new Point(-1, 1, 1), Vector.UnitX); Assert.True(box.IntersectsRay(ray, 0, double.PositiveInfinity)); box = new AxisAlignedBoundingBox(new Point(0, 0, 0), new Point(2, 2, 2)); ray = new Ray(new Point(1, -1, 1), Vector.UnitY); Assert.True(box.IntersectsRay(ray, 0, double.PositiveInfinity)); box = new AxisAlignedBoundingBox(new Point(0, 0, 0), new Point(2, 2, 2)); ray = new Ray(new Point(1, 1, -1), Vector.UnitZ); Assert.True(box.IntersectsRay(ray, 0, double.PositiveInfinity)); }
private static Mesh CreateHullMesh(Mesh mesh) { var bounds = AxisAlignedBoundingBox.Empty(); // Get the convex hull for the mesh var cHVertexList = new List <CHVertex>(); foreach (var position in mesh.Vertices.Distinct().ToArray()) { cHVertexList.Add(new CHVertex(position)); bounds.ExpandToInclude(position); } var tollerance = .01; if (cHVertexList.Count == 0 || bounds.XSize <= tollerance || bounds.YSize <= tollerance || bounds.ZSize <= tollerance || double.IsNaN(cHVertexList.First().Position[0])) { return(mesh); } var convexHull = ConvexHull <CHVertex, CHFace> .Create(cHVertexList, tollerance); if (convexHull != null) { // create the mesh from the hull data Mesh hullMesh = new Mesh(); foreach (var face in convexHull.Faces) { int vertexCount = hullMesh.Vertices.Count; foreach (var vertex in face.Vertices) { hullMesh.Vertices.Add(new Vector3(vertex.Position[0], vertex.Position[1], vertex.Position[2])); } hullMesh.Faces.Add(vertexCount, vertexCount + 1, vertexCount + 2, hullMesh.Vertices); } try { // make sure there is not currently a convex hull on this object if (mesh.PropertyBag.ContainsKey(ConvexHullMesh)) { mesh.PropertyBag.Remove(ConvexHullMesh); } // add the new hull mesh.PropertyBag.Add(ConvexHullMesh, hullMesh); // make sure we remove this hull if the mesh changes mesh.Changed += MeshChanged_RemoveConvexHull; // remove the marker that says we are building the hull if (mesh.PropertyBag.ContainsKey(CreatingConvexHullMesh)) { mesh.PropertyBag.Remove(CreatingConvexHullMesh); } return(hullMesh); } catch { } } return(null); }
public MoveTo(AxisAlignedBoundingBox nCurrentAABB, AxisAlignedBoundingBox nDesiredAABB) { currentAABB = nCurrentAABB; desiredAABB = nDesiredAABB; type = Type.MoveTo; }
public override AxisAlignedBoundingBox GetAxisAlignedBoundingBox() { AxisAlignedBoundingBox childBounds = objectToTransform.GetAxisAlignedBoundingBox(); return(childBounds.NewTransformed(transform)); }
public override List <WidgetAndPosition> FindDescendants(IEnumerable <string> namesToSearchFor, List <WidgetAndPosition> foundChildren, RectangleDouble touchingBounds, SearchType seachType, bool allowInvalidItems = true) { foreach (Object3DControl child in this.Object3DControls) { string object3DName = child.Name; bool nameFound = false; foreach (var nameToSearchFor in namesToSearchFor) { if (seachType == SearchType.Exact) { if (object3DName == nameToSearchFor) { nameFound = true; break; } } else { if (nameToSearchFor == "" || object3DName.Contains(nameToSearchFor)) { nameFound = true; break; } } } if (nameFound && child.CollisionVolume != null) { AxisAlignedBoundingBox bounds = child.CollisionVolume.GetAxisAlignedBoundingBox(); bounds = bounds.NewTransformed(child.TotalTransform); RectangleDouble screenBoundsOfObject3D = RectangleDouble.ZeroIntersection; for (int i = 0; i < 4; i++) { screenBoundsOfObject3D.ExpandToInclude(this.World.GetScreenPosition(bounds.GetTopCorner(i))); screenBoundsOfObject3D.ExpandToInclude(this.World.GetScreenPosition(bounds.GetBottomCorner(i))); } if (touchingBounds.IsTouching(screenBoundsOfObject3D)) { Vector3 renderPosition = bounds.Center; Vector2 objectCenterScreenSpace = this.World.GetScreenPosition(renderPosition); var screenPositionOfObject3D = new Point2D((int)objectCenterScreenSpace.X, (int)objectCenterScreenSpace.Y); foundChildren.Add(new WidgetAndPosition(this, screenPositionOfObject3D, object3DName, child)); } } } foreach (var child in scene.Children) { string object3DName = child.Name; if (object3DName == null && child.MeshPath != null) { object3DName = Path.GetFileName(child.MeshPath); } bool nameFound = false; foreach (var nameToSearchFor in namesToSearchFor) { if (seachType == SearchType.Exact) { if (object3DName == nameToSearchFor) { nameFound = true; break; } } else { if (nameToSearchFor == "" || object3DName.Contains(nameToSearchFor)) { nameFound = true; break; } } } if (nameFound) { AxisAlignedBoundingBox bounds = child.GetBVHData().GetAxisAlignedBoundingBox(); RectangleDouble screenBoundsOfObject3D = RectangleDouble.ZeroIntersection; for (int i = 0; i < 4; i++) { screenBoundsOfObject3D.ExpandToInclude(this.World.GetScreenPosition(bounds.GetTopCorner(i))); screenBoundsOfObject3D.ExpandToInclude(this.World.GetScreenPosition(bounds.GetBottomCorner(i))); } if (touchingBounds.IsTouching(screenBoundsOfObject3D)) { Vector3 renderPosition = bounds.Center; Vector2 objectCenterScreenSpace = this.World.GetScreenPosition(renderPosition); var screenPositionOfObject3D = new Point2D((int)objectCenterScreenSpace.X, (int)objectCenterScreenSpace.Y); foundChildren.Add(new WidgetAndPosition(this, screenPositionOfObject3D, object3DName, child)); } } } return(base.FindDescendants(namesToSearchFor, foundChildren, touchingBounds, seachType, allowInvalidItems)); }
public ActorAtmosphere() { Mesh = new MeshSphere((float)(SgpConstants.EarthRadiusKm / 100 + 0.7), 96, 48); BoundingBox = new AxisAlignedBoundingBox(new Vector3(140, 140, 140), Vector3.Zero, true); _shader = new ShaderProgram(ShaderBank.AtmosphereFrag, ShaderBank.AtmosphereVert); }
public MoveInZControl(IObject3DControlContext context) : base(context) { theme = AppContext.Theme; Name = "MoveInZControl"; zHeightDisplayInfo = new InlineEditControl() { ForceHide = () => { var selectedItem = RootSelection; // if the selection changes if (selectedItem != ActiveSelectedItem) { return(true); } // if another control gets a hover if (Object3DControlContext.HoveredObject3DControl != this && Object3DControlContext.HoveredObject3DControl != null) { return(true); } // if we clicked on the control if (hadClickOnControl) { return(false); } return(false); }, GetDisplayString = (value) => "{0:0.0#}".FormatWith(value) }; zHeightDisplayInfo.VisibleChanged += (s, e) => { if (!zHeightDisplayInfo.Visible) { hadClickOnControl = false; } }; zHeightDisplayInfo.EditComplete += (s, e) => { var selectedItem = RootSelection; Matrix4X4 startingTransform = selectedItem.Matrix; var newZPosition = zHeightDisplayInfo.Value; if (Object3DControlContext.SnapGridDistance > 0) { // snap this position to the grid double snapGridDistance = Object3DControlContext.SnapGridDistance; // snap this position to the grid newZPosition = ((int)((newZPosition / snapGridDistance) + .5)) * snapGridDistance; } AxisAlignedBoundingBox originalSelectedBounds = selectedItem.GetAxisAlignedBoundingBox(); var moveAmount = newZPosition - originalSelectedBounds.MinXYZ.Z; if (moveAmount != 0) { selectedItem.Matrix *= Matrix4X4.CreateTranslation(0, 0, moveAmount); Invalidate(); } context.Scene.AddTransformSnapshot(startingTransform); }; Object3DControlContext.GuiSurface.AddChild(zHeightDisplayInfo); DrawOnTop = true; using (Stream arrowStream = StaticData.Instance.OpenStream(Path.Combine("Stls", "up_pointer.stl"))) { upArrowMesh = StlProcessing.Load(arrowStream, CancellationToken.None); } CollisionVolume = upArrowMesh.CreateBVHData(); Object3DControlContext.GuiSurface.BeforeDraw += Object3DControl_BeforeDraw; }
public ScaleMatrixTopControl(IObject3DControlContext context) : base(context) { theme = AppContext.Theme; zValueDisplayInfo = new InlineEditControl() { ForceHide = () => { // if the selection changes if (RootSelection != activeSelectedItem) { return(true); } // if another control gets a hover if (Object3DControlContext.HoveredObject3DControl != this && Object3DControlContext.HoveredObject3DControl != null) { return(true); } // if we clicked on the control if (hadClickOnControl) { return(false); } return(false); }, GetDisplayString = (value) => "{0:0.0}".FormatWith(value) }; zValueDisplayInfo.VisibleChanged += (s, e) => { if (!zValueDisplayInfo.Visible) { hadClickOnControl = false; } }; zValueDisplayInfo.EditComplete += (s, e) => { var selectedItem = activeSelectedItem; Matrix4X4 startingTransform = selectedItem.Matrix; var originalSelectedBounds = selectedItem.GetAxisAlignedBoundingBox(); Vector3 topPosition = GetTopPosition(selectedItem); var lockedBottom = new Vector3(topPosition.X, topPosition.Y, originalSelectedBounds.MinXYZ.Z); Vector3 newSize = Vector3.Zero; newSize.Z = zValueDisplayInfo.Value; Vector3 scaleAmount = ScaleCornerControl.GetScalingConsideringShiftKey(originalSelectedBounds, mouseDownSelectedBounds, newSize, Object3DControlContext.GuiSurface.ModifierKeys); var scale = Matrix4X4.CreateScale(scaleAmount); selectedItem.Matrix = selectedItem.ApplyAtBoundsCenter(scale); // and keep the locked edge in place AxisAlignedBoundingBox scaledSelectedBounds = selectedItem.GetAxisAlignedBoundingBox(); var newLockedBottom = new Vector3(topPosition.X, topPosition.Y, scaledSelectedBounds.MinXYZ.Z); selectedItem.Matrix *= Matrix4X4.CreateTranslation(lockedBottom - newLockedBottom); Invalidate(); Object3DControlContext.Scene.AddTransformSnapshot(startingTransform); }; Object3DControlContext.GuiSurface.AddChild(zValueDisplayInfo); DrawOnTop = true; topScaleMesh = PlatonicSolids.CreateCube(arrowSize, arrowSize, arrowSize); CollisionVolume = topScaleMesh.CreateBVHData(); Object3DControlContext.GuiSurface.BeforeDraw += Object3DControl_BeforeDraw; }
public MoveInZControl(IInteractionVolumeContext context) : base(context) { Name = "MoveInZControl"; zHeightDisplayInfo = new InlineEditControl() { ForceHide = () => { var selectedItem = InteractionContext.Scene.RootSelectedItem; // if the selection changes if (selectedItem != ActiveSelectedItem) { return(true); } // if another control gets a hover if (InteractionContext.HoveredInteractionVolume != this && InteractionContext.HoveredInteractionVolume != null) { return(true); } // if we clicked on the control if (HadClickOnControl) { return(false); } return(false); } , GetDisplayString = (value) => "{0:0.0#}mm".FormatWith(value) }; zHeightDisplayInfo.VisibleChanged += (s, e) => { if (!zHeightDisplayInfo.Visible) { HadClickOnControl = false; } }; zHeightDisplayInfo.EditComplete += (s, e) => { var selectedItem = InteractionContext.Scene.RootSelectedItem; Matrix4X4 startingTransform = selectedItem.Matrix; var newZPosition = zHeightDisplayInfo.Value; if (InteractionContext.SnapGridDistance > 0) { // snap this position to the grid double snapGridDistance = InteractionContext.SnapGridDistance; // snap this position to the grid newZPosition = ((int)((newZPosition / snapGridDistance) + .5)) * snapGridDistance; } AxisAlignedBoundingBox originalSelectedBounds = selectedItem.GetAxisAlignedBoundingBox(Matrix4X4.Identity); var moveAmount = newZPosition - originalSelectedBounds.minXYZ.Z; if (moveAmount != 0) { selectedItem.Matrix = selectedItem.Matrix * Matrix4X4.CreateTranslation(0, 0, moveAmount); Invalidate(); } context.AddTransformSnapshot(startingTransform); }; InteractionContext.GuiSurface.AddChild(zHeightDisplayInfo); DrawOnTop = true; string arrowFile = Path.Combine("Icons", "3D Icons", "up_pointer.stl"); using (Stream arrowStream = AggContext.StaticData.OpenStream(arrowFile)) { upArrowMesh = MeshFileIo.Load(arrowStream, Path.GetExtension(arrowFile), CancellationToken.None).Mesh; } CollisionVolume = upArrowMesh.CreateTraceData(); InteractionContext.GuiSurface.AfterDraw += InteractionLayer_AfterDraw; }
public override void SetPosition() { if (MeshViewerToDrawWith.HaveSelection) { // draw the hight from the bottom to the bed AxisAlignedBoundingBox selectedBounds = MeshViewerToDrawWith.GetBoundsForSelection(); MeshSelectInfo meshSelectInfo = view3DWidget.CurrentSelectInfo; switch (meshSelectInfo.HitQuadrant) { case HitQuadrant.LB: { Vector3 cornerPoint = new Vector3(selectedBounds.minXYZ.x, selectedBounds.minXYZ.y, 0); double distBetweenPixelsWorldSpace = MeshViewerToDrawWith.TrackballTumbleWidget.GetWorldUnitsPerScreenPixelAtPosition(cornerPoint); lines[0] = MeshViewerToDrawWith.TrackballTumbleWidget.GetScreenPosition(cornerPoint - new Vector3(distToStart * distBetweenPixelsWorldSpace, 0, 0)); lines[1] = MeshViewerToDrawWith.TrackballTumbleWidget.GetScreenPosition(cornerPoint - new Vector3((distToStart + lineLength) * distBetweenPixelsWorldSpace, 0, 0)); lines[2] = MeshViewerToDrawWith.TrackballTumbleWidget.GetScreenPosition(cornerPoint - new Vector3(0, distToStart * distBetweenPixelsWorldSpace, 0)); lines[3] = MeshViewerToDrawWith.TrackballTumbleWidget.GetScreenPosition(cornerPoint - new Vector3(0, (distToStart + lineLength) * distBetweenPixelsWorldSpace, 0)); } break; case HitQuadrant.LT: { Vector3 cornerPoint = new Vector3(selectedBounds.minXYZ.x, selectedBounds.maxXYZ.y, 0); double distBetweenPixelsWorldSpace = MeshViewerToDrawWith.TrackballTumbleWidget.GetWorldUnitsPerScreenPixelAtPosition(cornerPoint); lines[0] = MeshViewerToDrawWith.TrackballTumbleWidget.GetScreenPosition(cornerPoint - new Vector3(distToStart * distBetweenPixelsWorldSpace, 0, 0)); lines[1] = MeshViewerToDrawWith.TrackballTumbleWidget.GetScreenPosition(cornerPoint - new Vector3((distToStart + lineLength) * distBetweenPixelsWorldSpace, 0, 0)); lines[2] = MeshViewerToDrawWith.TrackballTumbleWidget.GetScreenPosition(cornerPoint + new Vector3(0, distToStart * distBetweenPixelsWorldSpace, 0)); lines[3] = MeshViewerToDrawWith.TrackballTumbleWidget.GetScreenPosition(cornerPoint + new Vector3(0, (distToStart + lineLength) * distBetweenPixelsWorldSpace, 0)); } break; case HitQuadrant.RB: { Vector3 cornerPoint = new Vector3(selectedBounds.maxXYZ.x, selectedBounds.minXYZ.y, 0); double distBetweenPixelsWorldSpace = MeshViewerToDrawWith.TrackballTumbleWidget.GetWorldUnitsPerScreenPixelAtPosition(cornerPoint); lines[0] = MeshViewerToDrawWith.TrackballTumbleWidget.GetScreenPosition(cornerPoint + new Vector3(distToStart * distBetweenPixelsWorldSpace, 0, 0)); lines[1] = MeshViewerToDrawWith.TrackballTumbleWidget.GetScreenPosition(cornerPoint + new Vector3((distToStart + lineLength) * distBetweenPixelsWorldSpace, 0, 0)); lines[2] = MeshViewerToDrawWith.TrackballTumbleWidget.GetScreenPosition(cornerPoint - new Vector3(0, distToStart * distBetweenPixelsWorldSpace, 0)); lines[3] = MeshViewerToDrawWith.TrackballTumbleWidget.GetScreenPosition(cornerPoint - new Vector3(0, (distToStart + lineLength) * distBetweenPixelsWorldSpace, 0)); } break; case HitQuadrant.RT: { Vector3 cornerPoint = new Vector3(selectedBounds.maxXYZ.x, selectedBounds.maxXYZ.y, 0); double distBetweenPixelsWorldSpace = MeshViewerToDrawWith.TrackballTumbleWidget.GetWorldUnitsPerScreenPixelAtPosition(cornerPoint); lines[0] = MeshViewerToDrawWith.TrackballTumbleWidget.GetScreenPosition(cornerPoint + new Vector3(distToStart * distBetweenPixelsWorldSpace, 0, 0)); lines[1] = MeshViewerToDrawWith.TrackballTumbleWidget.GetScreenPosition(cornerPoint + new Vector3((distToStart + lineLength) * distBetweenPixelsWorldSpace, 0, 0)); lines[2] = MeshViewerToDrawWith.TrackballTumbleWidget.GetScreenPosition(cornerPoint + new Vector3(0, distToStart * distBetweenPixelsWorldSpace, 0)); lines[3] = MeshViewerToDrawWith.TrackballTumbleWidget.GetScreenPosition(cornerPoint + new Vector3(0, (distToStart + lineLength) * distBetweenPixelsWorldSpace, 0)); } break; } } }
public static Mesh[] SplitIntoMeshesOnOrthographicZ(Mesh meshToSplit, Vector3 buildVolume, BackgroundWorker backgroundWorker, int startPercent, int endPercent) { int lengthPercent = endPercent - startPercent; // check if the part is bigger than the build plate (if it is we need to use that as our size) AxisAlignedBoundingBox partBounds = meshToSplit.GetAxisAlignedBoundingBox(); buildVolume.x = Math.Max(buildVolume.x, partBounds.XSize + 2); buildVolume.y = Math.Max(buildVolume.y, partBounds.YSize + 2); buildVolume.z = Math.Max(buildVolume.z, partBounds.ZSize + 2); // Find all the separate objects that are on the plate // Create a 2D image the size of the printer bed at some scale with the parts draw on it top down double scaleFactor = 5; ImageBuffer partPlate = new ImageBuffer((int)(buildVolume.x * scaleFactor), (int)(buildVolume.y * scaleFactor), 32, new BlenderBGRA()); Vector2 renderOffset = new Vector2(buildVolume.x / 2, buildVolume.y / 2) - new Vector2(partBounds.Center.x, partBounds.Center.y); PolygonMesh.Rendering.OrthographicZProjection.DrawTo(partPlate.NewGraphics2D(), meshToSplit, renderOffset, scaleFactor, RGBA_Bytes.White); if (backgroundWorker != null) { backgroundWorker.ReportProgress(startPercent + (int)(lengthPercent * .2)); } //ImageIO.SaveImageData("test part plate 0.png", partPlate); // expand the bounds a bit so that we can collect all the vertices and polygons within each bound Dilate.DoDilate3x3Binary(partPlate, 1); //ImageIO.SaveImageData("test part plate 1.png", partPlate); // trace all the bounds of the objects on the plate PolyTree polyTreeForPlate = FindDistictObjectBounds(partPlate); if (polyTreeForPlate == null) { Mesh[] singleMesh = new Mesh[1]; singleMesh[0] = meshToSplit; return(singleMesh); } // get all the discrete areas that are polygons so we can search them Polygons discreteAreas = new Polygons(); GetAreasRecursive(polyTreeForPlate, discreteAreas); if (discreteAreas.Count == 0) { return(null); } else if (discreteAreas.Count == 1) { Mesh[] singleMesh = new Mesh[1]; singleMesh[0] = meshToSplit; return(singleMesh); } Graphics2D graphics2D = partPlate.NewGraphics2D(); graphics2D.Clear(RGBA_Bytes.Black); Random rand = new Random(); foreach (Polygon polygon in discreteAreas) { graphics2D.Render(PlatingHelper.PolygonToPathStorage(polygon), new RGBA_Bytes(rand.Next(128, 255), rand.Next(128, 255), rand.Next(128, 255))); } if (backgroundWorker != null) { backgroundWorker.ReportProgress(startPercent + (int)(lengthPercent * .50)); } //ImageIO.SaveImageData("test part plate 2.png", partPlate); // add each of the separate bounds polygons to new meshes Mesh[] discreteMeshes = new Mesh[discreteAreas.Count]; for (int i = 0; i < discreteAreas.Count; i++) { discreteMeshes[i] = new Mesh(); } foreach (Face face in meshToSplit.Faces) { bool faceDone = false; // figure out which area one or more of the vertices are in add the face to the right new mesh foreach (FaceEdge faceEdge in face.FaceEdges()) { Vector2 position = new Vector2(faceEdge.firstVertex.Position.x, faceEdge.firstVertex.Position.y); position += renderOffset; position *= scaleFactor; for (int areaIndex = discreteAreas.Count - 1; areaIndex >= 0; areaIndex--) { if (PointInPolygon(discreteAreas[areaIndex], new IntPoint((int)position.x, (int)position.y))) { List <Vertex> faceVertices = new List <Vertex>(); foreach (FaceEdge faceEdgeToAdd in face.FaceEdges()) { Vertex newVertex = discreteMeshes[areaIndex].CreateVertex(faceEdgeToAdd.firstVertex.Position); faceVertices.Add(newVertex); } discreteMeshes[areaIndex].CreateFace(faceVertices.ToArray()); faceDone = true; break; } } if (faceDone) { break; } } } if (backgroundWorker != null) { backgroundWorker.ReportProgress(startPercent + (int)(lengthPercent)); } for (int i = 0; i < discreteMeshes.Count(); i++) { Mesh mesh = discreteMeshes[i]; } return(discreteMeshes); }
public Task Create(IProgress <ProgressStatus> progress, CancellationToken cancellationToken) { var selectedItem = scene.SelectedItem; using (new SelectionMaintainer(scene)) { var status = new ProgressStatus { Status = "Enter" }; progress?.Report(status); // Get visible meshes for each of them var allBedItems = scene.Children.SelectMany(i => i.VisibleMeshes()); var suppoortBounds = AxisAlignedBoundingBox.Empty(); if (selectedItem != null) { foreach (var candidate in selectedItem.VisibleMeshes()) { suppoortBounds += candidate.GetAxisAlignedBoundingBox(candidate.Matrix.Inverted * candidate.WorldMatrix()); } } else { foreach (var candidate in allBedItems) { suppoortBounds += candidate.GetAxisAlignedBoundingBox(candidate.Matrix.Inverted * candidate.WorldMatrix()); } } // create the gird of possible support var gridBounds = new RectangleDouble(Math.Floor((double)(suppoortBounds.MinXYZ.X / PillarSize)), Math.Floor((double)(suppoortBounds.MinXYZ.Y / PillarSize)), Math.Ceiling(suppoortBounds.MaxXYZ.X / PillarSize), Math.Ceiling(suppoortBounds.MaxXYZ.Y / PillarSize)); var partBounds = new RectangleDouble(gridBounds.Left * PillarSize, gridBounds.Bottom * PillarSize, gridBounds.Right * PillarSize, gridBounds.Top * PillarSize); int gridWidth = (int)gridBounds.Width; int gridHeight = (int)gridBounds.Height; var supportGrid = new List <List <List <(bool isBottom, double z)> > >(); for (int x = 0; x < gridWidth; x++) { supportGrid.Add(new List <List <(bool, double)> >()); for (int y = 0; y < gridHeight; y++) { supportGrid[x].Add(new List <(bool, double)>()); } } // get all the support plane intersections status.Status = "Trace"; progress?.Report(status); var detectedPlanes = DetectRequiredSupportByTracing(gridBounds, allBedItems); status.Status = "Columns"; progress?.Report(status); // minimum height requiring support is 1/2 the layer height AddSupportColumns(gridBounds, detectedPlanes); // this is the theory for regions rather than pillars // separate the faces into face patch groups (these are the new support tops) // project all the vertices of each patch group down until they hit an up face in the scene (or 0) // make a new patch group at the z of the hit (these will be the bottoms) // find the outline of the patch groups (these will be the walls of the top and bottom patches // make a new mesh object with the top, bottom and walls, add it to the scene and mark it as support return(Task.CompletedTask); } }
public static void MakeLowestFaceFlat(this InteractiveScene scene, IObject3D objectToLayFlatGroup) { var preLayFlatMatrix = objectToLayFlatGroup.Matrix; bool firstVertex = true; IObject3D objectToLayFlat = objectToLayFlatGroup; Vector3Float lowestPosition = Vector3Float.PositiveInfinity; Vector3Float sourceVertexPosition = Vector3Float.NegativeInfinity; IObject3D itemToLayFlat = null; Mesh meshWithLowest = null; var items = objectToLayFlat.VisibleMeshes().Where(i => i.OutputType != PrintOutputTypes.Support); if (!items.Any()) { items = objectToLayFlat.VisibleMeshes(); } // Process each child, checking for the lowest vertex foreach (var itemToCheck in items) { var meshToCheck = itemToCheck.Mesh.GetConvexHull(false); if (meshToCheck == null && meshToCheck.Vertices.Count < 3) { continue; } // find the lowest point on the model for (int testIndex = 0; testIndex < meshToCheck.Vertices.Count; testIndex++) { var vertex = meshToCheck.Vertices[testIndex]; var vertexPosition = vertex.Transform(itemToCheck.WorldMatrix()); if (firstVertex) { meshWithLowest = meshToCheck; lowestPosition = vertexPosition; sourceVertexPosition = vertex; itemToLayFlat = itemToCheck; firstVertex = false; } else if (vertexPosition.Z < lowestPosition.Z) { meshWithLowest = meshToCheck; lowestPosition = vertexPosition; sourceVertexPosition = vertex; itemToLayFlat = itemToCheck; } } } if (meshWithLowest == null) { // didn't find any selected mesh return; } int faceToLayFlat = -1; double largestAreaOfAnyFace = 0; var facesSharingLowestVertex = meshWithLowest.Faces .Select((face, i) => new { face, i }) .Where(faceAndIndex => meshWithLowest.Vertices[faceAndIndex.face.v0] == sourceVertexPosition || meshWithLowest.Vertices[faceAndIndex.face.v1] == sourceVertexPosition || meshWithLowest.Vertices[faceAndIndex.face.v2] == sourceVertexPosition) .Select(j => j.i); var lowestFacesByAngle = facesSharingLowestVertex.OrderBy(i => { var face = meshWithLowest.Faces[i]; var worldNormal = face.normal.TransformNormal(itemToLayFlat.WorldMatrix()); return(worldNormal.CalculateAngle(-Vector3Float.UnitZ)); }); // Check all the faces that are connected to the lowest point to find out which one to lay flat. foreach (var faceIndex in lowestFacesByAngle) { var face = meshWithLowest.Faces[faceIndex]; var worldNormal = face.normal.TransformNormal(itemToLayFlat.WorldMatrix()); var worldAngleDegrees = MathHelper.RadiansToDegrees(worldNormal.CalculateAngle(-Vector3Float.UnitZ)); double largestAreaFound = 0; var faceVeretexIndices = new int[] { face.v0, face.v1, face.v2 }; foreach (var vi in faceVeretexIndices) { if (meshWithLowest.Vertices[vi] != lowestPosition) { var planSurfaceArea = 0.0; foreach (var coPlanarFace in meshWithLowest.GetCoplanerFaces(faceIndex)) { planSurfaceArea += meshWithLowest.GetSurfaceArea(coPlanarFace); } if (largestAreaOfAnyFace == 0 || (planSurfaceArea > largestAreaFound && worldAngleDegrees < 45)) { largestAreaFound = planSurfaceArea; } } } if (largestAreaFound > largestAreaOfAnyFace) { largestAreaOfAnyFace = largestAreaFound; faceToLayFlat = faceIndex; } } double maxDistFromLowestZ = 0; var lowestFace = meshWithLowest.Faces[faceToLayFlat]; var lowestFaceIndices = new int[] { lowestFace.v0, lowestFace.v1, lowestFace.v2 }; var faceVertices = new List <Vector3Float>(); foreach (var vertex in lowestFaceIndices) { var vertexPosition = meshWithLowest.Vertices[vertex].Transform(itemToLayFlat.WorldMatrix()); faceVertices.Add(vertexPosition); maxDistFromLowestZ = Math.Max(maxDistFromLowestZ, vertexPosition.Z - lowestPosition.Z); } if (maxDistFromLowestZ > .001) { var xPositive = (faceVertices[1] - faceVertices[0]).GetNormal(); var yPositive = (faceVertices[2] - faceVertices[0]).GetNormal(); var planeNormal = xPositive.Cross(yPositive).GetNormal(); // this code takes the minimum rotation required and looks much better. Quaternion rotation = new Quaternion(planeNormal, new Vector3Float(0, 0, -1)); Matrix4X4 partLevelMatrix = Matrix4X4.CreateRotation(rotation); // rotate it objectToLayFlat.Matrix = objectToLayFlatGroup.ApplyAtBoundsCenter(partLevelMatrix); } if (objectToLayFlatGroup is Object3D object3D) { AxisAlignedBoundingBox bounds = object3D.GetAxisAlignedBoundingBox(Matrix4X4.Identity, (item) => { return(item.OutputType != PrintOutputTypes.Support); }); Vector3 boundsCenter = (bounds.MaxXYZ + bounds.MinXYZ) / 2; object3D.Matrix *= Matrix4X4.CreateTranslation(new Vector3(0, 0, -boundsCenter.Z + bounds.ZSize / 2)); } else { PlatingHelper.PlaceOnBed(objectToLayFlatGroup); } scene.UndoBuffer.Add(new TransformCommand(objectToLayFlatGroup, preLayFlatMatrix, objectToLayFlatGroup.Matrix)); }
public void FrustumIntersetAABBTests() { { Frustum frustum = new Frustum( new Plane(new Vector3(1, 0, 0), 20), new Plane(new Vector3(-1, 0, 0), 20), new Plane(new Vector3(0, 1, 0), 20), new Plane(new Vector3(0, -1, 0), 20), new Plane(new Vector3(0, 0, 1), 20), new Plane(new Vector3(0, 0, -1), 20)); // outside to left { AxisAlignedBoundingBox aabb = new AxisAlignedBoundingBox(new Vector3(-30, -10, -10), new Vector3(-25, 10, 10)); FrustumIntersection intersection = frustum.GetIntersect(aabb); Assert.IsTrue(intersection == FrustumIntersection.Outside); } // intersect { AxisAlignedBoundingBox aabb = new AxisAlignedBoundingBox(new Vector3(-25, 0, -10), new Vector3(-15, 10, 10)); FrustumIntersection intersection = frustum.GetIntersect(aabb); Assert.IsTrue(intersection == FrustumIntersection.Intersect); } // not intersect { AxisAlignedBoundingBox aabb = new AxisAlignedBoundingBox(new Vector3(-25, 0, 30), new Vector3(-15, 10, 35)); FrustumIntersection intersection = frustum.GetIntersect(aabb); Assert.IsTrue(intersection == FrustumIntersection.Outside); } // inside { AxisAlignedBoundingBox aabb = new AxisAlignedBoundingBox(new Vector3(-5, -5, -5), new Vector3(5, 5, 5)); FrustumIntersection intersection = frustum.GetIntersect(aabb); Assert.IsTrue(intersection == FrustumIntersection.Inside); } } { Frustum frustum = new Frustum( new Plane(new Vector3(-1, -1, 0), 0), new Plane(new Vector3(1, -1, 0), 0), new Plane(new Vector3(0, -1, -1), 0), new Plane(new Vector3(0, -1, 1), 0), new Plane(new Vector3(0, -1, 0), 0), new Plane(new Vector3(0, 1, 0), 10000)); // outside to left { AxisAlignedBoundingBox aabb = new AxisAlignedBoundingBox(new Vector3(-110, 0, -10), new Vector3(-100, 10, 10)); FrustumIntersection intersection = frustum.GetIntersect(aabb); Assert.IsTrue(intersection == FrustumIntersection.Outside); } // intersect with origin (front) { AxisAlignedBoundingBox aabb = new AxisAlignedBoundingBox(new Vector3(-10, -10, -10), new Vector3(10, 10, 10)); FrustumIntersection intersection = frustum.GetIntersect(aabb); Assert.IsTrue(intersection == FrustumIntersection.Intersect); } // inside { AxisAlignedBoundingBox aabb = new AxisAlignedBoundingBox(new Vector3(-5, 100, -5), new Vector3(5, 110, 5)); FrustumIntersection intersection = frustum.GetIntersect(aabb); Assert.IsTrue(intersection == FrustumIntersection.Inside); } } { // looking down -z Frustum frustum5PlaneNegZ = new Frustum( new Vector3(-1, 0, 1), new Vector3(-1, 0, 1), new Vector3(0, 1, 1), new Vector3(0, -1, 1), new Vector3(0, 0, -1), 10000); // outside to left { AxisAlignedBoundingBox aabb = new AxisAlignedBoundingBox(new Vector3(-110, 0, -10), new Vector3(-100, 10, 10)); FrustumIntersection intersection = frustum5PlaneNegZ.GetIntersect(aabb); Assert.IsTrue(intersection == FrustumIntersection.Outside); } // intersect with origin (front) { AxisAlignedBoundingBox aabb = new AxisAlignedBoundingBox(new Vector3(-10, -10, -10), new Vector3(10, 10, 10)); FrustumIntersection intersection = frustum5PlaneNegZ.GetIntersect(aabb); Assert.IsTrue(intersection == FrustumIntersection.Intersect); } // inside { AxisAlignedBoundingBox aabb = new AxisAlignedBoundingBox(new Vector3(-5, -5, -110), new Vector3(5, 5, -100)); FrustumIntersection intersection = frustum5PlaneNegZ.GetIntersect(aabb); Assert.IsTrue(intersection == FrustumIntersection.Inside); } } }
public Vector3 GetTopPosition(IObject3D selectedItem) { AxisAlignedBoundingBox originalSelectedBounds = selectedItem.GetAxisAlignedBoundingBox(); return(new Vector3(originalSelectedBounds.Center.X, originalSelectedBounds.Center.Y, originalSelectedBounds.MaxXYZ.Z)); }
public static IBoundedItem CreateNewHierachy(List <IBoundedItem> traceableItems, int maxRecursion = int.MaxValue, int recursionDepth = 0, SortingAccelerator accelerator = null) { if (accelerator == null) { accelerator = new SortingAccelerator(); } int numItems = traceableItems.Count; if (numItems == 0) { return(null); } if (numItems == 1) { return(traceableItems[0]); } int bestAxis = -1; int bestIndexToSplitOn = -1; CompareCentersOnAxis axisSorter = new CompareCentersOnAxis(0); if (recursionDepth < maxRecursion) { if (numItems > 5000) { bestAxis = accelerator.NextAxis; bestIndexToSplitOn = numItems / 2; } else { double totalIntersectCost = 0; int skipInterval = 1; for (int i = 0; i < numItems; i += skipInterval) { IBoundedItem item = traceableItems[i]; totalIntersectCost += item.GetIntersectCost(); } // get the bounding box of all the items we are going to consider. AxisAlignedBoundingBox OverallBox = traceableItems[0].GetAxisAlignedBoundingBox(); for (int i = skipInterval; i < numItems; i += skipInterval) { OverallBox += traceableItems[i].GetAxisAlignedBoundingBox(); } double areaOfTotalBounds = OverallBox.GetSurfaceArea(); double bestCost = totalIntersectCost; Vector3 totalDeviationOnAxis = new Vector3(); double[] surfaceArreaOfItem = new double[numItems - 1]; double[] rightBoundsAtItem = new double[numItems - 1]; for (int axis = 0; axis < 3; axis++) { double intersectCostOnLeft = 0; axisSorter.WhichAxis = axis; traceableItems.Sort(axisSorter); // Get all left bounds AxisAlignedBoundingBox currentLeftBounds = traceableItems[0].GetAxisAlignedBoundingBox(); surfaceArreaOfItem[0] = currentLeftBounds.GetSurfaceArea(); for (int itemIndex = 1; itemIndex < numItems - 1; itemIndex += skipInterval) { currentLeftBounds += traceableItems[itemIndex].GetAxisAlignedBoundingBox(); surfaceArreaOfItem[itemIndex] = currentLeftBounds.GetSurfaceArea(); totalDeviationOnAxis[axis] += Math.Abs(traceableItems[itemIndex].GetCenter()[axis] - traceableItems[itemIndex - 1].GetCenter()[axis]); } // Get all right bounds if (numItems > 1) { AxisAlignedBoundingBox currentRightBounds = traceableItems[numItems - 1].GetAxisAlignedBoundingBox(); rightBoundsAtItem[numItems - 2] = currentRightBounds.GetSurfaceArea(); for (int itemIndex = numItems - 1; itemIndex > 1; itemIndex -= skipInterval) { currentRightBounds += traceableItems[itemIndex - 1].GetAxisAlignedBoundingBox(); rightBoundsAtItem[itemIndex - 2] = currentRightBounds.GetSurfaceArea(); } } // Sweep from left for (int itemIndex = 0; itemIndex < numItems - 1; itemIndex += skipInterval) { double thisCost = 0; { // Evaluate Surface Cost Equation double costOfTwoAABB = 2 * AxisAlignedBoundingBox.GetIntersectCost(); // the cost of the two children AABB tests // do the left cost intersectCostOnLeft += traceableItems[itemIndex].GetIntersectCost(); double leftCost = (surfaceArreaOfItem[itemIndex] / areaOfTotalBounds) * intersectCostOnLeft; // do the right cost double intersectCostOnRight = totalIntersectCost - intersectCostOnLeft; double rightCost = (rightBoundsAtItem[itemIndex] / areaOfTotalBounds) * intersectCostOnRight; thisCost = costOfTwoAABB + leftCost + rightCost; } if (thisCost < bestCost + .000000001) // if it is less within some tiny error { if (thisCost > bestCost - .000000001) { // they are the same within the error if (axis > 0 && bestAxis != axis) // we have changed axis since last best and we need to decide if this is better than the last axis best { if (totalDeviationOnAxis[axis] > totalDeviationOnAxis[axis - 1]) { // this new axis is better and we'll switch to it. Otherwise don't switch. bestCost = thisCost; bestIndexToSplitOn = itemIndex; bestAxis = axis; } } } else // this is just better { bestCost = thisCost; bestIndexToSplitOn = itemIndex; bestAxis = axis; } } } } } } if (bestAxis == -1) { // No better partition found return(new UnboundCollection(traceableItems)); } else { axisSorter.WhichAxis = bestAxis; traceableItems.Sort(axisSorter); List <IBoundedItem> leftItems = new List <IBoundedItem>(bestIndexToSplitOn + 1); List <IBoundedItem> rightItems = new List <IBoundedItem>(numItems - bestIndexToSplitOn + 1); for (int i = 0; i <= bestIndexToSplitOn; i++) { leftItems.Add(traceableItems[i]); } for (int i = bestIndexToSplitOn + 1; i < numItems; i++) { rightItems.Add(traceableItems[i]); } IBoundedItem leftGroup = CreateNewHierachy(leftItems, maxRecursion, recursionDepth + 1, accelerator); IBoundedItem rightGroup = CreateNewHierachy(rightItems, maxRecursion, recursionDepth + 1, accelerator); BoundingVolumeHierarchy newBVHNode = new BoundingVolumeHierarchy(leftGroup, rightGroup, bestAxis); return(newBVHNode); } }
public override void OnMouseMove(Mouse3DEventArgs mouseEvent3D, bool mouseIsOver) { var selectedItem = RootSelection; activeSelectedItem = selectedItem; if (MouseIsOver) { zValueDisplayInfo.Visible = true; } else if (!hadClickOnControl) { zValueDisplayInfo.Visible = false; } if (MouseDownOnControl) { IntersectInfo info = hitPlane.GetClosestIntersection(mouseEvent3D.MouseRay); if (info != null && selectedItem != null) { AxisAlignedBoundingBox originalSelectedBounds = selectedItem.GetAxisAlignedBoundingBox(); Vector3 delta = info.HitPosition - initialHitPosition; Vector3 newPosition = originalPointToMove + delta; if (Object3DControlContext.SnapGridDistance > 0) { // snap this position to the grid double snapGridDistance = Object3DControlContext.SnapGridDistance; // snap this position to the grid newPosition.Z = ((int)((newPosition.Z / snapGridDistance) + .5)) * snapGridDistance; } Vector3 topPosition = GetTopPosition(selectedItem); var lockedBottom = new Vector3(topPosition.X, topPosition.Y, originalSelectedBounds.MinXYZ.Z); Vector3 newSize = Vector3.Zero; newSize.Z = newPosition.Z - lockedBottom.Z; // scale it Vector3 scaleAmount = ScaleCornerControl.GetScalingConsideringShiftKey(originalSelectedBounds, mouseDownSelectedBounds, newSize, Object3DControlContext.GuiSurface.ModifierKeys); var scale = Matrix4X4.CreateScale(scaleAmount); selectedItem.Matrix = selectedItem.ApplyAtBoundsCenter(scale); // and keep the locked edge in place AxisAlignedBoundingBox scaledSelectedBounds = selectedItem.GetAxisAlignedBoundingBox(); var newLockedBottom = new Vector3(topPosition.X, topPosition.Y, scaledSelectedBounds.MinXYZ.Z); selectedItem.Matrix *= Matrix4X4.CreateTranslation(lockedBottom - newLockedBottom); Invalidate(); } } base.OnMouseMove(mouseEvent3D, mouseIsOver); }
public CenterAndHeightMantainer(IObject3D item) { this.item = item; aabb = item.GetAxisAlignedBoundingBox(); }
public double GetIntersectCost() { return(AxisAlignedBoundingBox.GetIntersectCost()); }
private static bool CheckPosition(IEnumerable <IObject3D> itemsToAvoid, IObject3D itemToMove, AxisAlignedBoundingBox meshToMoveBounds, int yStep, int xStep, out Matrix4X4 transform) { double xStepAmount = 5; double yStepAmount = 5; var positionTransform = Matrix4X4.CreateTranslation(xStep * xStepAmount, yStep * yStepAmount, 0); Vector3 newPosition = Vector3Ex.Transform(Vector3.Zero, positionTransform); transform = Matrix4X4.CreateTranslation(newPosition); AxisAlignedBoundingBox testBounds = meshToMoveBounds.NewTransformed(transform); foreach (IObject3D meshToTest in itemsToAvoid) { if (meshToTest != itemToMove) { AxisAlignedBoundingBox existingMeshBounds = meshToTest.GetAxisAlignedBoundingBox(); var intersection = AxisAlignedBoundingBox.Intersection(testBounds, existingMeshBounds); if (intersection.XSize > 0 && intersection.YSize > 0) { return(false); } } } return(true); }
public void BuildBoundingBox() { BoundingBox = new AxisAlignedBoundingBox(new Vector3(Center.X - Radius, Center.Y - Radius, Center.Z - Radius), new Vector3(Center.X + Radius, Center.Y + Radius, Center.Z + Radius)); }
public static void ArrangeMeshGroups(List <MeshGroup> asyncMeshGroups, List <Matrix4X4> asyncMeshGroupTransforms, List <PlatingMeshGroupData> asyncPlatingDatas, Action <double, string> reportProgressChanged) { // move them all out of the way for (int i = 0; i < asyncMeshGroups.Count; i++) { asyncMeshGroupTransforms[i] *= Matrix4X4.CreateTranslation(10000, 10000, 0); } // sort them by size for (int i = 0; i < asyncMeshGroups.Count; i++) { AxisAlignedBoundingBox iAABB = asyncMeshGroups[i].GetAxisAlignedBoundingBox(asyncMeshGroupTransforms[i]); for (int j = i + 1; j < asyncMeshGroups.Count; j++) { AxisAlignedBoundingBox jAABB = asyncMeshGroups[j].GetAxisAlignedBoundingBox(asyncMeshGroupTransforms[j]); if (Math.Max(iAABB.XSize, iAABB.YSize) < Math.Max(jAABB.XSize, jAABB.YSize)) { PlatingMeshGroupData tempData = asyncPlatingDatas[i]; asyncPlatingDatas[i] = asyncPlatingDatas[j]; asyncPlatingDatas[j] = tempData; MeshGroup tempMeshGroup = asyncMeshGroups[i]; asyncMeshGroups[i] = asyncMeshGroups[j]; asyncMeshGroups[j] = tempMeshGroup; Matrix4X4 iTransform = asyncMeshGroupTransforms[i]; Matrix4X4 jTransform = asyncMeshGroupTransforms[j]; Matrix4X4 tempTransform = iTransform; iTransform = jTransform; jTransform = tempTransform; asyncMeshGroupTransforms[i] = jTransform; asyncMeshGroupTransforms[j] = iTransform; iAABB = jAABB; } } } double ratioPerMeshGroup = 1.0 / asyncMeshGroups.Count; double currentRatioDone = 0; // put them onto the plate (try the center) starting with the biggest and moving down for (int meshGroupIndex = 0; meshGroupIndex < asyncMeshGroups.Count; meshGroupIndex++) { reportProgressChanged(currentRatioDone, "Calculating Positions...".Localize()); MeshGroup meshGroup = asyncMeshGroups[meshGroupIndex]; Vector3 meshLowerLeft = meshGroup.GetAxisAlignedBoundingBox(asyncMeshGroupTransforms[meshGroupIndex]).minXYZ; asyncMeshGroupTransforms[meshGroupIndex] *= Matrix4X4.CreateTranslation(-meshLowerLeft); PlatingHelper.MoveMeshGroupToOpenPosition(meshGroupIndex, asyncPlatingDatas, asyncMeshGroups, asyncMeshGroupTransforms); // and create the trace info so we can select it if (asyncPlatingDatas[meshGroupIndex].meshTraceableData.Count == 0) { PlatingHelper.CreateITraceableForMeshGroup(asyncPlatingDatas, asyncMeshGroups, meshGroupIndex, null); } currentRatioDone += ratioPerMeshGroup; // and put it on the bed PlatingHelper.PlaceMeshGroupOnBed(asyncMeshGroups, asyncMeshGroupTransforms, meshGroupIndex); } // and finally center whatever we have as a group { AxisAlignedBoundingBox bounds = asyncMeshGroups[0].GetAxisAlignedBoundingBox(asyncMeshGroupTransforms[0]); for (int i = 1; i < asyncMeshGroups.Count; i++) { bounds = AxisAlignedBoundingBox.Union(bounds, asyncMeshGroups[i].GetAxisAlignedBoundingBox(asyncMeshGroupTransforms[i])); } Vector3 boundsCenter = (bounds.maxXYZ + bounds.minXYZ) / 2; for (int i = 0; i < asyncMeshGroups.Count; i++) { asyncMeshGroupTransforms[i] *= Matrix4X4.CreateTranslation(-boundsCenter + new Vector3(0, 0, bounds.ZSize / 2)); } } }
public void SavingFunction() { currentlySaving = true; countThatHaveBeenSaved = 0; // first create images for all the parts foreach (FileNameAndPresentationName queuePartFileName in queuPartFilesToAdd) { List <MeshGroup> loadedMeshGroups = MeshFileIo.Load(queuePartFileName.fileName); if (loadedMeshGroups != null) { bool firstMeshGroup = true; AxisAlignedBoundingBox aabb = null; foreach (MeshGroup meshGroup in loadedMeshGroups) { if (firstMeshGroup) { aabb = meshGroup.GetAxisAlignedBoundingBox(); firstMeshGroup = false; } else { aabb = AxisAlignedBoundingBox.Union(aabb, meshGroup.GetAxisAlignedBoundingBox()); } } RectangleDouble bounds2D = new RectangleDouble(aabb.minXYZ.x, aabb.minXYZ.y, aabb.maxXYZ.x, aabb.maxXYZ.y); double widthInMM = bounds2D.Width + PartMarginMM * 2; double textSpaceMM = 5; double heightMM = textSpaceMM + bounds2D.Height + PartMarginMM * 2; TypeFacePrinter typeFacePrinter = new TypeFacePrinter(queuePartFileName.presentationName, 28, Vector2.Zero, Justification.Center, Baseline.BoundsCenter); double sizeOfNameX = typeFacePrinter.GetSize().x + PartMarginPixels * 2; Vector2 sizeOfRender = new Vector2(widthInMM * PixelPerMM, heightMM * PixelPerMM); ImageBuffer imageOfPart = new ImageBuffer((int)(Math.Max(sizeOfNameX, sizeOfRender.x)), (int)(sizeOfRender.y), 32, new BlenderBGRA()); typeFacePrinter.Origin = new Vector2(imageOfPart.Width / 2, (textSpaceMM / 2) * PixelPerMM); Graphics2D partGraphics2D = imageOfPart.NewGraphics2D(); RectangleDouble rectBounds = new RectangleDouble(0, 0, imageOfPart.Width, imageOfPart.Height); double strokeWidth = .5 * PixelPerMM; rectBounds.Inflate(-strokeWidth / 2); RoundedRect rect = new RoundedRect(rectBounds, PartMarginMM * PixelPerMM); partGraphics2D.Render(rect, RGBA_Bytes.LightGray); Stroke rectOutline = new Stroke(rect, strokeWidth); partGraphics2D.Render(rectOutline, RGBA_Bytes.DarkGray); foreach (MeshGroup meshGroup in loadedMeshGroups) { foreach (Mesh loadedMesh in meshGroup.Meshes) { PolygonMesh.Rendering.OrthographicZProjection.DrawTo(partGraphics2D, loadedMesh, new Vector2(-bounds2D.Left + PartMarginMM, -bounds2D.Bottom + textSpaceMM + PartMarginMM), PixelPerMM, RGBA_Bytes.Black); } } partGraphics2D.Render(typeFacePrinter, RGBA_Bytes.Black); partImagesToPrint.Add(new PartImage(imageOfPart)); countThatHaveBeenSaved++; } if (UpdateRemainingItems != null) { UpdateRemainingItems(this, new StringEventArgs(Path.GetFileName(queuePartFileName.presentationName))); } } partImagesToPrint.Sort(BiggestToLittlestImages); PdfDocument document = new PdfDocument(); document.Info.Title = "MatterHackers Parts Sheet"; document.Info.Author = "MatterHackers Inc."; document.Info.Subject = "This is a list of the parts that are in a queue from MatterControl."; document.Info.Keywords = "MatterControl, STL, 3D Printing"; int nextPartToPrintIndex = 0; int plateNumber = 1; bool done = false; while (!done && nextPartToPrintIndex < partImagesToPrint.Count) { PdfPage pdfPage = document.AddPage(); CreateOnePage(plateNumber++, ref nextPartToPrintIndex, pdfPage); } try { // save the final document document.Save(pathAndFileToSaveTo); // Now try and open the document. This will lanch whatever PDF viewer is on the system and ask it // to show the file (at least on Windows). Process.Start(pathAndFileToSaveTo); } catch (Exception) { } OnDoneSaving(); currentlySaving = false; }
public static void MoveMeshGroupToOpenPosition(int meshGroupToMoveIndex, List <PlatingMeshGroupData> perMeshInfo, List <MeshGroup> allMeshGroups, List <Matrix4X4> meshTransforms) { AxisAlignedBoundingBox allPlacedMeshBounds = GetAxisAlignedBoundingBox(allMeshGroups[0], meshTransforms[0]); for (int i = 1; i < meshGroupToMoveIndex; i++) { AxisAlignedBoundingBox nextMeshBounds = GetAxisAlignedBoundingBox(allMeshGroups[i], meshTransforms[i]); allPlacedMeshBounds = AxisAlignedBoundingBox.Union(allPlacedMeshBounds, nextMeshBounds); } double xStart = allPlacedMeshBounds.minXYZ.x; double yStart = allPlacedMeshBounds.minXYZ.y; MeshGroup meshGroupToMove = allMeshGroups[meshGroupToMoveIndex]; // find a place to put it that doesn't hit anything AxisAlignedBoundingBox meshToMoveBounds = GetAxisAlignedBoundingBox(meshGroupToMove, meshTransforms[meshGroupToMoveIndex]); // add in a few mm so that it will not be touching meshToMoveBounds.minXYZ -= new Vector3(2, 2, 0); meshToMoveBounds.maxXYZ += new Vector3(2, 2, 0); Matrix4X4 transform = Matrix4X4.Identity; int currentSize = 1; bool partPlaced = false; while (!partPlaced && meshGroupToMoveIndex > 0) { int yStep = 0; int xStep = currentSize; // check far right edge for (yStep = 0; yStep < currentSize; yStep++) { partPlaced = CheckPosition(meshGroupToMoveIndex, allMeshGroups, meshTransforms, meshGroupToMove, meshToMoveBounds, yStep, xStep, ref transform); if (partPlaced) { break; } } if (!partPlaced) { yStep = currentSize; // check top edge for (xStep = 0; xStep < currentSize; xStep++) { partPlaced = CheckPosition(meshGroupToMoveIndex, allMeshGroups, meshTransforms, meshGroupToMove, meshToMoveBounds, yStep, xStep, ref transform); if (partPlaced) { break; } } if (!partPlaced) { xStep = currentSize; // check top right point partPlaced = CheckPosition(meshGroupToMoveIndex, allMeshGroups, meshTransforms, meshGroupToMove, meshToMoveBounds, yStep, xStep, ref transform); } } currentSize++; } meshTransforms[meshGroupToMoveIndex] *= transform; }
private void AlignSelected() { if (SelectedMeshGroupIndex == -1) { SelectedMeshGroupIndex = 0; } // make sure our thread translates numbers correctly (always do this in a thread) Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; // save our data so we don't mess up the display while doing work PushMeshGroupDataToAsynchLists(TraceInfoOpperation.DO_COPY); // try to move all the not selected meshes relative to the selected mesh AxisAlignedBoundingBox selectedOriginalBounds = asyncMeshGroups[SelectedMeshGroupIndex].GetAxisAlignedBoundingBox(); Vector3 selectedOriginalCenter = selectedOriginalBounds.Center; AxisAlignedBoundingBox selectedCurrentBounds = asyncMeshGroups[SelectedMeshGroupIndex].GetAxisAlignedBoundingBox(asyncMeshGroupTransforms[SelectedMeshGroupIndex]); Vector3 selctedCurrentCenter = selectedCurrentBounds.Center; for (int meshGroupToMoveIndex = 0; meshGroupToMoveIndex < asyncMeshGroups.Count; meshGroupToMoveIndex++) { MeshGroup meshGroupToMove = asyncMeshGroups[meshGroupToMoveIndex]; if (meshGroupToMove != asyncMeshGroups[SelectedMeshGroupIndex]) { AxisAlignedBoundingBox groupToMoveOriginalBounds = meshGroupToMove.GetAxisAlignedBoundingBox(); Vector3 groupToMoveOriginalCenter = groupToMoveOriginalBounds.Center; AxisAlignedBoundingBox groupToMoveBounds = meshGroupToMove.GetAxisAlignedBoundingBox(asyncMeshGroupTransforms[meshGroupToMoveIndex]); Vector3 groupToMoveCenter = groupToMoveBounds.Center; Vector3 originalCoordinatesDelta = groupToMoveOriginalCenter - selectedOriginalCenter; Vector3 currentCoordinatesDelta = groupToMoveCenter - selctedCurrentCenter; Vector3 deltaRequired = originalCoordinatesDelta - currentCoordinatesDelta; if (deltaRequired.Length > .0001) { asyncMeshGroupTransforms[meshGroupToMoveIndex] *= Matrix4X4.CreateTranslation(deltaRequired); PartHasBeenChanged(); } } } // now put all the meshes into just one group MeshGroup meshGroupWeAreKeeping = asyncMeshGroups[SelectedMeshGroupIndex]; for (int meshGroupToMoveIndex = asyncMeshGroups.Count - 1; meshGroupToMoveIndex >= 0; meshGroupToMoveIndex--) { MeshGroup meshGroupToMove = asyncMeshGroups[meshGroupToMoveIndex]; if (meshGroupToMove != meshGroupWeAreKeeping) { // move all the meshes into the new aligned mesh group for (int moveIndex = 0; moveIndex < meshGroupToMove.Meshes.Count; moveIndex++) { Mesh mesh = meshGroupToMove.Meshes[moveIndex]; meshGroupWeAreKeeping.Meshes.Add(mesh); } asyncMeshGroups.RemoveAt(meshGroupToMoveIndex); asyncMeshGroupTransforms.RemoveAt(meshGroupToMoveIndex); } } asyncPlatingDatas.Clear(); double ratioPerMeshGroup = 1.0 / asyncMeshGroups.Count; double currentRatioDone = 0; for (int i = 0; i < asyncMeshGroups.Count; i++) { PlatingMeshGroupData newInfo = new PlatingMeshGroupData(); asyncPlatingDatas.Add(newInfo); MeshGroup meshGroup = asyncMeshGroups[i]; // create the selection info PlatingHelper.CreateITraceableForMeshGroup(asyncPlatingDatas, asyncMeshGroups, i, (double progress0To1, string processingState, out bool continueProcessing) => { ReportProgressChanged(progress0To1, processingState, out continueProcessing); }); currentRatioDone += ratioPerMeshGroup; } }
private static bool CheckPosition(int meshGroupToMoveIndex, List <MeshGroup> allMeshGroups, List <Matrix4X4> meshTransforms, MeshGroup meshGroupToMove, AxisAlignedBoundingBox meshToMoveBounds, int yStep, int xStep, ref Matrix4X4 transform) { double xStepAmount = 5; double yStepAmount = 5; Matrix4X4 positionTransform = Matrix4X4.CreateTranslation(xStep * xStepAmount, yStep * yStepAmount, 0); Vector3 newPosition = Vector3.Transform(Vector3.Zero, positionTransform); transform = Matrix4X4.CreateTranslation(newPosition); AxisAlignedBoundingBox testBounds = meshToMoveBounds.NewTransformed(transform); bool foundHit = false; for (int i = 0; i < meshGroupToMoveIndex; i++) { MeshGroup meshToTest = allMeshGroups[i]; if (meshToTest != meshGroupToMove) { AxisAlignedBoundingBox existingMeshBounds = GetAxisAlignedBoundingBox(meshToTest, meshTransforms[i]); AxisAlignedBoundingBox intersection = AxisAlignedBoundingBox.Intersection(testBounds, existingMeshBounds); if (intersection.XSize > 0 && intersection.YSize > 0) { foundHit = true; break; } } } if (!foundHit) { return(true); } return(false); }
public async Task SaveSheets() { await Task.Run((Func <Task>)(async() => { currentlySaving = true; // first create images for all the parts foreach (var item in itemSource) { var object3D = await item.CreateContent(); var loadedMeshGroups = object3D.VisibleMeshes().ToList(); if (loadedMeshGroups?.Count > 0) { AxisAlignedBoundingBox aabb = loadedMeshGroups[0].Mesh.GetAxisAlignedBoundingBox(loadedMeshGroups[0].WorldMatrix()); for (int i = 1; i < loadedMeshGroups.Count; i++) { aabb = AxisAlignedBoundingBox.Union(aabb, loadedMeshGroups[i].Mesh.GetAxisAlignedBoundingBox(loadedMeshGroups[i].WorldMatrix())); } RectangleDouble bounds2D = new RectangleDouble(aabb.minXYZ.X, aabb.minXYZ.Y, aabb.maxXYZ.X, aabb.maxXYZ.Y); double widthInMM = bounds2D.Width + PartMarginMM * 2; double textSpaceMM = 5; double heightMM = textSpaceMM + bounds2D.Height + PartMarginMM * 2; TypeFacePrinter typeFacePrinter = new TypeFacePrinter(item.Name, 28, Vector2.Zero, Justification.Center, Baseline.BoundsCenter); double sizeOfNameX = typeFacePrinter.GetSize().X + PartMarginPixels * 2; Vector2 sizeOfRender = new Vector2(widthInMM *PixelPerMM, heightMM *PixelPerMM); ImageBuffer imageOfPart = new ImageBuffer((int)(Math.Max(sizeOfNameX, sizeOfRender.X)), (int)(sizeOfRender.Y)); typeFacePrinter.Origin = new Vector2(imageOfPart.Width / 2, (textSpaceMM / 2) * PixelPerMM); Graphics2D partGraphics2D = imageOfPart.NewGraphics2D(); RectangleDouble rectBounds = new RectangleDouble(0, 0, imageOfPart.Width, imageOfPart.Height); double strokeWidth = .5 * PixelPerMM; rectBounds.Inflate(-strokeWidth / 2); RoundedRect rect = new RoundedRect(rectBounds, PartMarginMM *PixelPerMM); partGraphics2D.Render(rect, Color.LightGray); Stroke rectOutline = new Stroke(rect, strokeWidth); partGraphics2D.Render(rectOutline, Color.DarkGray); foreach (var meshGroup in loadedMeshGroups) { PolygonMesh.Rendering.OrthographicZProjection.DrawTo(partGraphics2D, meshGroup.Mesh, meshGroup.WorldMatrix(), new Vector2(-bounds2D.Left + PartMarginMM, -bounds2D.Bottom + textSpaceMM + PartMarginMM), PixelPerMM, Color.Black); } partGraphics2D.Render(typeFacePrinter, Color.Black); partImagesToPrint.Add(new PartImage(imageOfPart)); } UpdateRemainingItems?.Invoke(this, new StringEventArgs(item.Name)); } partImagesToPrint.Sort(BiggestToLittlestImages); PdfDocument document = new PdfDocument(); document.Info.Title = "MatterHackers Parts Sheet"; document.Info.Author = "MatterHackers Inc."; document.Info.Subject = "This is a list of the parts that are in a queue from MatterControl."; document.Info.Keywords = "MatterControl, STL, 3D Printing"; int nextPartToPrintIndex = 0; int plateNumber = 1; bool done = false; while (!done && nextPartToPrintIndex < partImagesToPrint.Count) { PdfPage pdfPage = document.AddPage(); CreateOnePage(plateNumber++, ref nextPartToPrintIndex, pdfPage); } try { // save the final document document.Save(pathAndFileToSaveTo); // Now try and open the document. This will launch whatever PDF viewer is on the system and ask it // to show the file (at least on Windows). Process.Start(pathAndFileToSaveTo); } catch (Exception) { } OnDoneSaving(); currentlySaving = false; })); }
public static Matrix4X4 ApplyAtCenter(AxisAlignedBoundingBox boundsToApplyTo, Matrix4X4 currentTransform, Matrix4X4 transformToApply) { return(ApplyAtPosition(currentTransform, transformToApply, boundsToApplyTo.Center)); }
public void UpdateBoundingBox() { var vertices = GetRawVertexList(); var a = vertices[0]; var b = vertices[0]; foreach(var v in vertices) { a = Min(a, v); b = Max(b, v); } AABB = new AxisAlignedBoundingBox() { Minimum = a, Maximum = b }; }
internal ModelMesh(W3dMesh w3dMesh, AssetLoadContext loadContext) { SetNameAndInstanceId("W3DMesh", w3dMesh.Header.MeshName); W3dShaderMaterial w3dShaderMaterial; ShaderResourcesBase shaderResources; if (w3dMesh.MaterialPasses.Count == 1 && w3dMesh.MaterialPasses[0].ShaderMaterialIds != null) { if (w3dMesh.MaterialPasses[0].ShaderMaterialIds.Items.Length > 1) { throw new NotSupportedException(); } var shaderMaterialID = w3dMesh.MaterialPasses[0].ShaderMaterialIds.Items[0]; w3dShaderMaterial = w3dMesh.ShaderMaterials.Items[(int)shaderMaterialID]; var effectName = w3dShaderMaterial.Header.TypeName.Replace(".fx", string.Empty); shaderResources = loadContext.ShaderResources.GetShaderMaterialResources(effectName); } else { w3dShaderMaterial = null; shaderResources = loadContext.ShaderResources.FixedFunction; } _depthPipeline = loadContext.ShaderResources.MeshDepth.Pipeline; MeshParts = new List <ModelMeshPart>(); if (w3dShaderMaterial != null) { MeshParts.Add(CreateModelMeshPartShaderMaterial( loadContext, w3dMesh, w3dMesh.MaterialPasses[0], w3dShaderMaterial, (ShaderMaterialShaderResources)shaderResources)); } else { var vertexMaterials = CreateMaterials(w3dMesh); var shadingConfigurations = new FixedFunctionShaderResources.ShadingConfiguration[w3dMesh.Shaders.Items.Count]; for (var i = 0; i < shadingConfigurations.Length; i++) { shadingConfigurations[i] = CreateShadingConfiguration(w3dMesh.Shaders.Items[i]); } for (var i = 0; i < w3dMesh.MaterialPasses.Count; i++) { CreateModelMeshPartsFixedFunction( loadContext, w3dMesh, w3dMesh.MaterialPasses[i], vertexMaterials, shadingConfigurations, MeshParts); } } BoundingBox = new AxisAlignedBoundingBox( w3dMesh.Header.Min, w3dMesh.Header.Max); _shaderSet = shaderResources.ShaderSet; Skinned = w3dMesh.IsSkinned; Hidden = w3dMesh.Header.Attributes.HasFlag(W3dMeshFlags.Hidden); CameraOriented = (w3dMesh.Header.Attributes & W3dMeshFlags.GeometryTypeMask) == W3dMeshFlags.GeometryTypeCameraOriented; _vertexBuffer = AddDisposable(loadContext.GraphicsDevice.CreateStaticBuffer( MemoryMarshal.AsBytes(new ReadOnlySpan <MeshShaderResources.MeshVertex.Basic>(CreateVertices(w3dMesh, w3dMesh.IsSkinned))), BufferUsage.VertexBuffer)); _indexBuffer = AddDisposable(loadContext.GraphicsDevice.CreateStaticBuffer( CreateIndices(w3dMesh), BufferUsage.IndexBuffer)); var hasHouseColor = w3dMesh.Header.MeshName.StartsWith("HOUSECOLOR"); _meshConstantsResourceSet = loadContext.ShaderResources.Mesh.GetCachedMeshResourceSet( Skinned, hasHouseColor); PostInitialize(loadContext); }
public void Contains(float x, float y, float z, bool expected) { var sut = new AxisAlignedBoundingBox(new Vector3(-2), new Vector3(2)); Assert.Equal(expected, sut.Contains(new Vector3(x, y, z))); }
public abstract bool CheckIfBundleHitsAabb(AxisAlignedBoundingBox aabbToCheck);