Commit of the code
This commit is contained in:
parent
33cee93974
commit
f4c1b0b85c
356 changed files with 175795 additions and 0 deletions
250
PartPreviewWindow/CreateDiscreteMeshes.cs
Normal file
250
PartPreviewWindow/CreateDiscreteMeshes.cs
Normal file
|
|
@ -0,0 +1,250 @@
|
|||
/*
|
||||
Copyright (c) 2013, Lars Brubaker
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of the FreeBSD Project.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.ComponentModel;
|
||||
|
||||
using MatterHackers.Agg;
|
||||
using MatterHackers.Agg.Image;
|
||||
using MatterHackers.Agg.ImageProcessing;
|
||||
using MatterHackers.Agg.VertexSource;
|
||||
using MatterHackers.MarchingSquares;
|
||||
using MatterHackers.PolygonMesh;
|
||||
using MatterHackers.PolygonMesh.Processors;
|
||||
using MatterHackers.VectorMath;
|
||||
|
||||
using ClipperLib;
|
||||
|
||||
namespace MatterHackers.MatterControl
|
||||
{
|
||||
using Polygon = List<IntPoint>;
|
||||
using Polygons = List<List<IntPoint>>;
|
||||
|
||||
public static class CreateDiscreteMeshes
|
||||
{
|
||||
public static Mesh[] SplitIntoMeshes(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.Processors.OrthographicZProjection.DrawTo(partPlate.NewGraphics2D(), meshToSplit, renderOffset, scaleFactor, RGBA_Bytes.White);
|
||||
|
||||
if (backgroundWorker != null)
|
||||
{
|
||||
backgroundWorker.ReportProgress(startPercent + (int)(lengthPercent * .2));
|
||||
}
|
||||
|
||||
//ImageBMPIO.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);
|
||||
//ImageBMPIO.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));
|
||||
}
|
||||
//ImageBMPIO.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.FaceEdgeIterator())
|
||||
{
|
||||
Vector2 position = new Vector2(faceEdge.vertex.Position.x, faceEdge.vertex.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.FaceEdgeIterator())
|
||||
{
|
||||
Vertex newVertex = discreteMeshes[areaIndex].CreateVertex(faceEdgeToAdd.vertex.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 static bool PointInPolygon(Polygon polygon, IntPoint testPosition)
|
||||
{
|
||||
int numPoints = polygon.Count;
|
||||
bool result = false;
|
||||
for (int i = 0; i < numPoints; i++)
|
||||
{
|
||||
int prevIndex = i - 1;
|
||||
if(prevIndex < 0)
|
||||
{
|
||||
prevIndex += numPoints;
|
||||
}
|
||||
|
||||
if ((((polygon[i].Y <= testPosition.Y) && (testPosition.Y < polygon[prevIndex].Y))
|
||||
|| ((polygon[prevIndex].Y <= testPosition.Y) && (testPosition.Y < polygon[i].Y)))
|
||||
&& (testPosition.X - polygon[i].X < (polygon[prevIndex].X - polygon[i].X) * (testPosition.Y - polygon[i].Y) / (polygon[prevIndex].Y - polygon[i].Y)))
|
||||
{
|
||||
result = !result;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static private void GetAreasRecursive(PolyNode polyTreeForPlate, Polygons discreteAreas)
|
||||
{
|
||||
if (!polyTreeForPlate.IsHole)
|
||||
{
|
||||
discreteAreas.Add(polyTreeForPlate.Contour);
|
||||
}
|
||||
|
||||
foreach (PolyNode child in polyTreeForPlate.Childs)
|
||||
{
|
||||
GetAreasRecursive(child, discreteAreas);
|
||||
}
|
||||
}
|
||||
|
||||
static public PolyTree FindDistictObjectBounds(ImageBuffer image)
|
||||
{
|
||||
MarchingSquaresByte marchingSquaresData = new MarchingSquaresByte(image, 5, 0);
|
||||
marchingSquaresData.CreateLineSegments();
|
||||
Polygons lineLoops = marchingSquaresData.CreateLineLoops(1);
|
||||
|
||||
if (lineLoops.Count == 1)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// create a bounding polygon to clip against
|
||||
IntPoint min = new IntPoint(long.MaxValue, long.MaxValue);
|
||||
IntPoint max = new IntPoint(long.MinValue, long.MinValue);
|
||||
foreach (Polygon polygon in lineLoops)
|
||||
{
|
||||
foreach (IntPoint point in polygon)
|
||||
{
|
||||
min.X = Math.Min(point.X - 10, min.X);
|
||||
min.Y = Math.Min(point.Y - 10, min.Y);
|
||||
max.X = Math.Max(point.X + 10, max.X);
|
||||
max.Y = Math.Max(point.Y + 10, max.Y);
|
||||
}
|
||||
}
|
||||
|
||||
Polygon boundingPoly = new Polygon();
|
||||
boundingPoly.Add(min);
|
||||
boundingPoly.Add(new IntPoint(min.X, max.Y));
|
||||
boundingPoly.Add(max);
|
||||
boundingPoly.Add(new IntPoint(max.X, min.Y));
|
||||
|
||||
// now clip the polygons to get the inside and outside polys
|
||||
Clipper clipper = new Clipper();
|
||||
clipper.AddPolygons(lineLoops, PolyType.ptSubject);
|
||||
clipper.AddPolygon(boundingPoly, PolyType.ptClip);
|
||||
|
||||
PolyTree polyTreeForPlate = new PolyTree();
|
||||
clipper.Execute(ClipType.ctIntersection, polyTreeForPlate);
|
||||
|
||||
return polyTreeForPlate;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue