Made MatterControl run as a .net standard app
Moving matter control to a lib and creating a new exe to run it
This commit is contained in:
parent
8b4790e493
commit
bed90234e7
485 changed files with 283 additions and 571 deletions
340
MatterControlLib/DesignTools/Primitives/BaseObject3D.cs
Normal file
340
MatterControlLib/DesignTools/Primitives/BaseObject3D.cs
Normal file
|
|
@ -0,0 +1,340 @@
|
|||
/*
|
||||
Copyright (c) 2018, Lars Brubaker, John Lewin
|
||||
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 ClipperLib;
|
||||
using MatterHackers.Agg.Transform;
|
||||
using MatterHackers.Agg.UI;
|
||||
using MatterHackers.Agg.VertexSource;
|
||||
using MatterHackers.DataConverters2D;
|
||||
using MatterHackers.DataConverters3D;
|
||||
using MatterHackers.Localizations;
|
||||
using MatterHackers.VectorMath;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace MatterHackers.MatterControl.DesignTools
|
||||
{
|
||||
using Polygon = List<IntPoint>;
|
||||
using Polygons = List<List<IntPoint>>;
|
||||
public enum BaseTypes { None, Rectangle, Circle, /* Oval, Frame,*/ Outline, };
|
||||
|
||||
public class BaseObject3D : Object3D, IPropertyGridModifier
|
||||
{
|
||||
readonly double scalingForClipper = 1000;
|
||||
|
||||
public BaseObject3D()
|
||||
{
|
||||
Name = "Base".Localize();
|
||||
}
|
||||
|
||||
public override bool CanApply => true;
|
||||
|
||||
public BaseTypes BaseType { get; set; } = BaseTypes.Circle;
|
||||
public double BaseSize { get; set; } = 3;
|
||||
public double InfillAmount { get; set; } = 3;
|
||||
public double ExtrusionHeight { get; set; } = 5;
|
||||
|
||||
public override void Apply(UndoBuffer undoBuffer)
|
||||
{
|
||||
base.Apply(undoBuffer);
|
||||
}
|
||||
|
||||
public override void Remove(UndoBuffer undoBuffer)
|
||||
{
|
||||
using (RebuildLock())
|
||||
{
|
||||
var startingAabb = this.GetAxisAlignedBoundingBox();
|
||||
|
||||
var firstChild = this.Children.FirstOrDefault();
|
||||
|
||||
// only keep the first object
|
||||
this.Children.Modify(list =>
|
||||
{
|
||||
list.Clear();
|
||||
// add back in the sourceContainer
|
||||
list.Add(firstChild);
|
||||
});
|
||||
|
||||
if (startingAabb.ZSize > 0)
|
||||
{
|
||||
// If the part was already created and at a height, maintain the height.
|
||||
PlatingHelper.PlaceMeshAtHeight(this, startingAabb.minXYZ.Z);
|
||||
}
|
||||
}
|
||||
|
||||
base.Remove(undoBuffer);
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public IVertexSource VertexSource
|
||||
{
|
||||
get
|
||||
{
|
||||
var vertexSource = (IPathObject)this.Descendants<IObject3D>().FirstOrDefault((i) => i is IPathObject);
|
||||
return vertexSource?.VertexSource;
|
||||
}
|
||||
set
|
||||
{
|
||||
var vertexSource = this.Children.OfType<IPathObject>().FirstOrDefault();
|
||||
if (vertexSource != null)
|
||||
{
|
||||
vertexSource.VertexSource = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static BaseObject3D Create()
|
||||
{
|
||||
var item = new BaseObject3D();
|
||||
item.Rebuild(null);
|
||||
return item;
|
||||
}
|
||||
|
||||
public override void OnInvalidate(InvalidateArgs invalidateType)
|
||||
{
|
||||
if ((invalidateType.InvalidateType == InvalidateType.Content
|
||||
|| invalidateType.InvalidateType == InvalidateType.Matrix
|
||||
|| invalidateType.InvalidateType == InvalidateType.Path
|
||||
|| invalidateType.InvalidateType == InvalidateType.Mesh)
|
||||
&& invalidateType.Source != this
|
||||
&& !RebuildLocked)
|
||||
{
|
||||
Rebuild(null);
|
||||
}
|
||||
else if (invalidateType.InvalidateType == InvalidateType.Properties
|
||||
&& invalidateType.Source == this)
|
||||
{
|
||||
Rebuild(null);
|
||||
}
|
||||
else
|
||||
{
|
||||
base.OnInvalidate(invalidateType);
|
||||
}
|
||||
}
|
||||
|
||||
private void Rebuild(UndoBuffer undoBuffer)
|
||||
{
|
||||
this.DebugDepth("Rebuild");
|
||||
|
||||
using (RebuildLock())
|
||||
{
|
||||
var startingAabb = this.GetAxisAlignedBoundingBox();
|
||||
|
||||
var firstChild = this.Children.FirstOrDefault();
|
||||
|
||||
// remove the base mesh we added
|
||||
this.Children.Modify(list =>
|
||||
{
|
||||
list.Clear();
|
||||
// add back in the sourceContainer
|
||||
list.Add(firstChild);
|
||||
});
|
||||
|
||||
// and create the base
|
||||
var vertexSource = this.VertexSource;
|
||||
|
||||
// Convert VertexSource into expected Polygons
|
||||
Polygons polygonShape = (vertexSource == null) ? null : vertexSource.CreatePolygons();
|
||||
GenerateBase(polygonShape, firstChild.GetAxisAlignedBoundingBox().minXYZ.Z);
|
||||
|
||||
if (startingAabb.ZSize > 0)
|
||||
{
|
||||
// If the part was already created and at a height, maintain the height.
|
||||
PlatingHelper.PlaceMeshAtHeight(this, startingAabb.minXYZ.Z);
|
||||
}
|
||||
}
|
||||
|
||||
Invalidate(new InvalidateArgs(this, InvalidateType.Mesh));
|
||||
}
|
||||
|
||||
private static Polygon GetBoundingPolygon(Polygons basePolygons)
|
||||
{
|
||||
var min = new IntPoint(long.MaxValue, long.MaxValue);
|
||||
var max = new IntPoint(long.MinValue, long.MinValue);
|
||||
|
||||
foreach (Polygon polygon in basePolygons)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
var 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));
|
||||
|
||||
return boundingPoly;
|
||||
}
|
||||
|
||||
private static Polygon GetBoundingCircle(Polygons basePolygons)
|
||||
{
|
||||
var min = new IntPoint(long.MaxValue, long.MaxValue);
|
||||
var max = new IntPoint(long.MinValue, long.MinValue);
|
||||
|
||||
foreach (Polygon polygon in basePolygons)
|
||||
{
|
||||
foreach (IntPoint point in polygon)
|
||||
{
|
||||
min.X = Math.Min(point.X, min.X);
|
||||
min.Y = Math.Min(point.Y, min.Y);
|
||||
max.X = Math.Max(point.X, max.X);
|
||||
max.Y = Math.Max(point.Y, max.Y);
|
||||
}
|
||||
}
|
||||
|
||||
IntPoint center = (max - min) / 2 + min;
|
||||
long maxRadius = 0;
|
||||
|
||||
foreach (Polygon polygon in basePolygons)
|
||||
{
|
||||
foreach (IntPoint point in polygon)
|
||||
{
|
||||
long radius = (point - center).Length();
|
||||
if (radius > maxRadius)
|
||||
{
|
||||
maxRadius = radius;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var boundingCircle = new Polygon();
|
||||
int numPoints = 100;
|
||||
|
||||
for (int i = 0; i < numPoints; i++)
|
||||
{
|
||||
double angle = i / 100.0 * Math.PI * 2.0;
|
||||
IntPoint newPointOnCircle = new IntPoint(Math.Cos(angle) * maxRadius, Math.Sin(angle) * maxRadius) + center;
|
||||
boundingCircle.Add(newPointOnCircle);
|
||||
}
|
||||
|
||||
return boundingCircle;
|
||||
}
|
||||
|
||||
private static PolyTree GetPolyTree(Polygons basePolygons)
|
||||
{
|
||||
// create a bounding polygon to clip against
|
||||
Polygon boundingPoly = GetBoundingPolygon(basePolygons);
|
||||
|
||||
var polyTreeForTrace = new PolyTree();
|
||||
|
||||
var clipper = new Clipper();
|
||||
clipper.AddPaths(basePolygons, PolyType.ptSubject, true);
|
||||
clipper.AddPath(boundingPoly, PolyType.ptClip, true);
|
||||
clipper.Execute(ClipType.ctIntersection, polyTreeForTrace);
|
||||
|
||||
return polyTreeForTrace;
|
||||
}
|
||||
|
||||
public void GenerateBase(Polygons polygonShape, double bottomWithoutBase)
|
||||
{
|
||||
if (polygonShape != null
|
||||
&& polygonShape.Select(p => p.Count).Sum() > 3)
|
||||
{
|
||||
Polygons polysToOffset = new Polygons();
|
||||
|
||||
switch (BaseType)
|
||||
{
|
||||
case BaseTypes.Rectangle:
|
||||
polysToOffset.Add(GetBoundingPolygon(polygonShape));
|
||||
break;
|
||||
|
||||
case BaseTypes.Circle:
|
||||
polysToOffset.Add(GetBoundingCircle(polygonShape));
|
||||
break;
|
||||
|
||||
case BaseTypes.Outline:
|
||||
PolyTree polyTreeForBase = GetPolyTree(polygonShape);
|
||||
foreach (PolyNode polyToOffset in polyTreeForBase.Childs)
|
||||
{
|
||||
polysToOffset.Add(polyToOffset.Contour);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (polysToOffset.Count > 0)
|
||||
{
|
||||
Polygons basePolygons;
|
||||
|
||||
if (BaseType == BaseTypes.Outline
|
||||
&& InfillAmount > 0)
|
||||
{
|
||||
basePolygons = Offset(polysToOffset, (BaseSize + InfillAmount) * scalingForClipper);
|
||||
basePolygons = Offset(basePolygons, -InfillAmount * scalingForClipper);
|
||||
}
|
||||
else
|
||||
{
|
||||
basePolygons = Offset(polysToOffset, BaseSize * scalingForClipper);
|
||||
}
|
||||
|
||||
basePolygons = ClipperLib.Clipper.CleanPolygons(basePolygons, 10);
|
||||
|
||||
VertexStorage rawVectorShape = basePolygons.PolygonToPathStorage();
|
||||
var vectorShape = new VertexSourceApplyTransform(rawVectorShape, Affine.NewScaling(1.0 / scalingForClipper));
|
||||
|
||||
var baseObject = new Object3D()
|
||||
{
|
||||
Mesh = VertexSourceToMesh.Extrude(vectorShape, zHeight: ExtrusionHeight)
|
||||
};
|
||||
Children.Add(baseObject);
|
||||
baseObject.Mesh.Translate(new Vector3(0, 0, -ExtrusionHeight + bottomWithoutBase));
|
||||
}
|
||||
else
|
||||
{
|
||||
// clear the mesh
|
||||
Mesh = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Polygons Offset(Polygons polygons, double distance)
|
||||
{
|
||||
var offseter = new ClipperOffset();
|
||||
offseter.AddPaths(polygons, JoinType.jtRound, EndType.etClosedPolygon);
|
||||
|
||||
var solution = new Polygons();
|
||||
offseter.Execute(ref solution, distance);
|
||||
|
||||
return solution;
|
||||
}
|
||||
|
||||
public void UpdateControls(PublicPropertyChange change)
|
||||
{
|
||||
//var editRow = context.GetEditRow((this.ID, nameof(InfillAmount)));
|
||||
//if (editRow != null) editRow.Visible = CurrentBaseType == BaseTypes.Outline;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue