170 lines
4.2 KiB
C#
170 lines
4.2 KiB
C#
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using Godot;
|
|
using TriangleNet.Geometry;
|
|
using TriangleNet.Meshing;
|
|
using TriangleNet.Meshing.Algorithm;
|
|
|
|
namespace Rokojori
|
|
{
|
|
public class Shape2
|
|
{
|
|
public List<Path2> paths = new List<Path2>();
|
|
|
|
public Shape2( params Path2[] paths )
|
|
{
|
|
this.paths.AddRange( paths );
|
|
}
|
|
|
|
public Shape2( List<Path2> paths )
|
|
{
|
|
this.paths.AddRange( paths );
|
|
}
|
|
|
|
Polygon _CreateTNetPolygon()
|
|
{
|
|
// RJLog.Log( "Creating polygon", paths.Count );
|
|
|
|
var polygon = new Polygon();
|
|
|
|
var index = 0;
|
|
paths.ForEach(
|
|
( path )=>
|
|
{
|
|
var vertices = Lists.Map( path.points, p => new Vertex( p.X, p.Y ) );
|
|
var isHole = path.isClockwise;
|
|
|
|
// RJLog.Log( "Adding contour", vertices.Count, isHole );
|
|
|
|
|
|
polygon.Add( new Contour( vertices, index ), isHole );
|
|
|
|
|
|
index ++;
|
|
}
|
|
);
|
|
|
|
return polygon;
|
|
}
|
|
|
|
public static List<List<ClipperLib.IntPoint>> ToClipperPaths( Shape2 s )
|
|
{
|
|
var paths = new List<List<ClipperLib.IntPoint>>();
|
|
|
|
s.paths.ForEach( p => paths.Add( Path2.ToClipperPath( p ) ) );
|
|
|
|
return paths;
|
|
}
|
|
|
|
public static Shape2 FromClipperPaths( List<List<ClipperLib.IntPoint>> paths )
|
|
{
|
|
var shape = new Shape2();
|
|
|
|
paths.ForEach( p => shape.paths.Add( Path2.FromClipperPath( p ) ) );
|
|
|
|
return shape;
|
|
}
|
|
|
|
public static Shape2 Boolean( Shape2 a, Shape2 b, Geometry2D.PolyBooleanOperation booleanOperation, bool simplify = true )
|
|
{
|
|
// RJLog.Log( "Using Clipper Library" );
|
|
|
|
var clipperPathsA = ToClipperPaths( a );
|
|
var clipperPathsB = ToClipperPaths( b );
|
|
|
|
var resultPaths = new List<List<ClipperLib.IntPoint>>();
|
|
|
|
var type = ClipperLib.ClipType.ctUnion;
|
|
|
|
if ( Geometry2D.PolyBooleanOperation.Difference == booleanOperation )
|
|
{
|
|
type = ClipperLib.ClipType.ctDifference;
|
|
}
|
|
else if ( Geometry2D.PolyBooleanOperation.Intersection == booleanOperation )
|
|
{
|
|
type = ClipperLib.ClipType.ctIntersection;
|
|
}
|
|
else if ( Geometry2D.PolyBooleanOperation.Xor == booleanOperation )
|
|
{
|
|
type = ClipperLib.ClipType.ctXor;
|
|
}
|
|
|
|
RJLog.Log( "ShapeBool", "type: " + type, "boolOp: " + booleanOperation, "A|B >>",clipperPathsA.Count, clipperPathsB.Count );
|
|
var clipper = new ClipperLib.Clipper();
|
|
clipper.AddPaths( clipperPathsA, ClipperLib.PolyType.ptSubject, true);
|
|
clipper.AddPaths( clipperPathsB, ClipperLib.PolyType.ptClip, true);
|
|
clipper.Execute( type, resultPaths );
|
|
|
|
if ( simplify )
|
|
{
|
|
resultPaths = ClipperLib.Clipper.SimplifyPolygons( resultPaths );
|
|
}
|
|
|
|
|
|
var s = new Shape2();
|
|
|
|
resultPaths.ForEach(
|
|
( r ) =>
|
|
{
|
|
s.paths.Add( Path2.FromClipperPath( r ) );
|
|
}
|
|
);
|
|
|
|
return s;
|
|
}
|
|
|
|
public MeshGeometry CreateMeshGeometry()
|
|
{
|
|
if ( paths.Count == 1 )
|
|
{
|
|
// RJLog.Log( "Only 1 path" );
|
|
return paths[ 0 ].CreateMeshGeometry();
|
|
}
|
|
|
|
var polygon = _CreateTNetPolygon();
|
|
|
|
var options = new ConstraintOptions();
|
|
var quality = new QualityOptions();
|
|
var triangulator = new Dwyer();
|
|
|
|
IMesh mesh = polygon.Triangulate( options, quality, triangulator );
|
|
|
|
int vertexCount = mesh.Vertices.Count;
|
|
int triangleCount = mesh.Triangles.Count;
|
|
|
|
var meshGeometry = new MeshGeometry();
|
|
|
|
meshGeometry.vertices = new List<Vector3>( vertexCount );
|
|
meshGeometry.uvs = new List<Vector2>( vertexCount );
|
|
meshGeometry.indices = new List<int>( triangleCount * 3 );
|
|
meshGeometry.normals = new List<Vector3>( vertexCount );
|
|
|
|
foreach ( var v in mesh.Vertices )
|
|
{
|
|
var x = (float)v.x;
|
|
var y = (float)v.y;
|
|
|
|
meshGeometry.vertices.Add( new Vector3( x, 0, y ) );
|
|
meshGeometry.uvs.Add( new Vector2( x, y ) );
|
|
meshGeometry.normals.Add( Vector3.Up );
|
|
}
|
|
|
|
|
|
foreach ( var t in mesh.Triangles )
|
|
{
|
|
var vertices = t.vertices;
|
|
|
|
var indicesList = new List<string>();
|
|
|
|
|
|
for ( int i = 0; i < vertices.Length; i++ )
|
|
{
|
|
meshGeometry.indices.Add( t.GetVertexID( i ) );
|
|
}
|
|
}
|
|
|
|
|
|
return meshGeometry;
|
|
}
|
|
}
|
|
} |