Mesh
using Autodesk.DesignScript.Geometry.Properties;
using Autodesk.DesignScript.Interfaces;
using Autodesk.DesignScript.Runtime;
using DynamoServices;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Autodesk.DesignScript.Geometry
{
    public class Mesh : DesignScriptEntity
    {
        internal IMeshEntity MeshEntity => HostImpl as IMeshEntity;
        public IndexGroup[] FaceIndices => IndexGroup.Wrap(MeshEntity.get_FaceIndices(), true);
        [Scaling()]
        public Vector[] VertexNormals {
            get {
                return Vector.Wrap((from x in (IEnumerable<IVectorEntity>)MeshEntity.get_VertexNormals()
                select x.Scale(1 / DesignScriptEntity.scaleFactor)).ToArray(), true);
            }
        }
        public Point[] VertexPositions => Point.Wrap(MeshEntity.get_VertexPositions(), true);
        public int VertexCount => MeshEntity.get_VertexCount();
        public int EdgeCount => MeshEntity.get_EdgeCount();
        public int TriangleCount => MeshEntity.get_TriangleCount();
        public double Volume => MeshEntity.get_Volume() * Math.Pow(DesignScriptEntity.scaleFactor, 3);
        public double Area => MeshEntity.get_Area() * Math.Pow(DesignScriptEntity.scaleFactor, 2);
        public IEnumerable<double> VerticesAsThreeNumbers => (from x in MeshEntity.get_VerticesAsThreeNumbers()
        select x * DesignScriptEntity.scaleFactor).ToArray();
        public IEnumerable<double> EdgesAsSixNumbers => (from x in MeshEntity.get_EdgesAsSixNumbers()
        select x * DesignScriptEntity.scaleFactor).ToArray();
        public IEnumerable<double> TrianglesAsNineNumbers => (from x in MeshEntity.get_TrianglesAsNineNumbers()
        select x * DesignScriptEntity.scaleFactor).ToArray();
        internal Mesh(IMeshEntity host, bool persist)
            : base(host, persist)
        {
        }
        public override string ToString()
        {
            return "Mesh";
        }
        internal static Mesh Wrap(IMeshEntity host, bool persist = true)
        {
            if (host == null)
                return null;
            return new Mesh(host, persist);
        }
        internal static Mesh[] Wrap(IMeshEntity[] hosts, bool persist = true)
        {
            return (from x in hosts
            select Wrap(x, persist)).ToArray();
        }
        internal static Mesh[][] Wrap(IMeshEntity[][] hosts, bool persist = true)
        {
            return (from x in hosts
            select Wrap(x, persist)).ToArray();
        }
        internal static IMeshEntity[][] Unwrap(Mesh[][] o)
        {
            return (from x in o
            select Unwrap(x)).ToArray();
        }
        internal static IMeshEntity[] Unwrap(Mesh[] o)
        {
            return (from x in o
            select Unwrap(x)).ToArray();
        }
        internal static IMeshEntity[] Unwrap(IEnumerable<Mesh> o)
        {
            return (from x in o
            select Unwrap(x)).ToArray();
        }
        internal static IMeshEntity Unwrap(Mesh o)
        {
            return o.MeshEntity;
        }
        [IsVisibleInDynamoLibrary(false)]
        [IsObsolete("mesh_bypointsfaceindices_deprecated", typeof(Resources))]
        [Obsolete("This method is deprecated and will be removed in a future version of Dynamo. Use  Mesh.ByPointsIndexGroups (Point[] points, IndexGroup[] indexGroups) instead")]
        public static Mesh ByPointsFaceIndices(IEnumerable<Point> vertexPositions, IEnumerable<IndexGroup> indices)
        {
            LogWarningMessageEvents.OnLogInfoMessage(Resources.MeshPrecisionInfo);
            return Wrap(HostFactory.Factory.MeshByPointsFaceIndices(Point.Unwrap(vertexPositions), IndexGroup.Unwrap(indices)), true);
        }
        public static Mesh ByPointsIndexGroups(IEnumerable<Point> points, IEnumerable<IndexGroup> indexGroups)
        {
            LogWarningMessageEvents.OnLogInfoMessage(Resources.MeshPrecisionInfo);
            return Wrap(HostFactory.Factory.MeshByPointsFaceIndices(Point.Unwrap(points), IndexGroup.Unwrap(indexGroups)), true);
        }
        public static Mesh[] ImportFile(string fileName)
        {
            LogWarningMessageEvents.OnLogInfoMessage(Resources.MeshPrecisionInfo);
            return Wrap(HostFactory.Factory.MeshImportFile(fileName), true);
        }
        public static Mesh ByGeometry(Geometry inputGeometry, double tolerance = -1, int maxGridLines = 512)
        {
            LogWarningMessageEvents.OnLogInfoMessage(Resources.MeshPrecisionInfo);
            return Wrap(HostFactory.Factory.MeshByGeometry(Geometry.Unwrap(inputGeometry), tolerance, maxGridLines), true);
        }
        public static string ExportMeshes(string filename, IEnumerable<Mesh> meshes)
        {
            LogWarningMessageEvents.OnLogInfoMessage(Resources.MeshPrecisionInfo);
            return HostFactory.Factory.MeshExportMeshes(filename, Unwrap(meshes));
        }
        [IsVisibleInDynamoLibrary(false)]
        [IsObsolete("mesh_byverticesandindices_deprecated", typeof(Resources))]
        [Obsolete("This method is deprecated and will be removed in a future version of Dynamo. Use Mesh.ByPointsIndices (Point[] points, int[] indices) instead")]
        public static Mesh ByVerticesAndIndices(IEnumerable<Point> vertices, IEnumerable<int> indices)
        {
            LogWarningMessageEvents.OnLogInfoMessage(Resources.MeshPrecisionInfo);
            return Wrap(HostFactory.Factory.MeshByVerticesAndIndices(Point.Unwrap(vertices), indices), true);
        }
        public static Mesh ByPointsIndices(IEnumerable<Point> points, IEnumerable<int> indices)
        {
            LogWarningMessageEvents.OnLogInfoMessage(Resources.MeshPrecisionInfo);
            return Wrap(HostFactory.Factory.MeshByVerticesAndIndices(Point.Unwrap(points), indices), true);
        }
        public static Mesh Plane([DefaultArgument("Autodesk.DesignScript.Geometry.Point.ByCoordinates(0,0,0)")] Point origin, [Scaling()] double xWidth = 1, [Scaling()] double yWidth = 1, int xDivisions = 0, int yDivisions = 0)
        {
            LogWarningMessageEvents.OnLogInfoMessage(Resources.MeshPrecisionInfo);
            DesignScriptEntity.CheckArgsForAsmExtents(new List<double> {
                xWidth,
                yWidth
            });
            xWidth /= DesignScriptEntity.scaleFactor;
            yWidth /= DesignScriptEntity.scaleFactor;
            return Wrap(HostFactory.Factory.MeshPlane(Point.Unwrap(origin), xWidth, yWidth, xDivisions, yDivisions), true);
        }
        public static Mesh Cuboid([DefaultArgument("Autodesk.DesignScript.Geometry.Point.ByCoordinates(0,0,0)")] Point origin, double length = 1, double width = 1, double height = 1, int xDivisions = 0, int yDivisions = 0, int zDivisions = 0)
        {
            LogWarningMessageEvents.OnLogInfoMessage(Resources.MeshPrecisionInfo);
            DesignScriptEntity.CheckArgsForAsmExtents(new List<double> {
                width,
                length,
                height
            });
            width /= DesignScriptEntity.scaleFactor;
            length /= DesignScriptEntity.scaleFactor;
            height /= DesignScriptEntity.scaleFactor;
            return Wrap(HostFactory.Factory.MeshCuboid(Point.Unwrap(origin), length, width, height, xDivisions, yDivisions, zDivisions), true);
        }
        public static Mesh Sphere([DefaultArgument("Autodesk.DesignScript.Geometry.Point.ByCoordinates(0,0,0)")] Point origin, double radius = 1, int divisions = 0, bool icosphere = true)
        {
            LogWarningMessageEvents.OnLogInfoMessage(Resources.MeshPrecisionInfo);
            DesignScriptEntity.CheckArgsForAsmExtents(new List<double> {
                radius
            });
            radius /= DesignScriptEntity.scaleFactor;
            return Wrap(HostFactory.Factory.MeshSphere(Point.Unwrap(origin), radius, divisions, icosphere), true);
        }
        public static Mesh Cone([DefaultArgument("Autodesk.DesignScript.Geometry.Point.ByCoordinates(0,0,0)")] Point origin, double baseRadius = 1, double topRadius = 0, double height = 1, int divisions = 0, bool cap = true)
        {
            LogWarningMessageEvents.OnLogInfoMessage(Resources.MeshPrecisionInfo);
            DesignScriptEntity.CheckArgsForAsmExtents(new List<double> {
                baseRadius,
                topRadius,
                height
            });
            baseRadius /= DesignScriptEntity.scaleFactor;
            topRadius /= DesignScriptEntity.scaleFactor;
            height /= DesignScriptEntity.scaleFactor;
            return Wrap(HostFactory.Factory.MeshCone(Point.Unwrap(origin), baseRadius, topRadius, height, divisions, cap), true);
        }
        public static Mesh ExtrudePolyCurve(PolyCurve polycurve, double height, Vector direction, bool cap = false)
        {
            LogWarningMessageEvents.OnLogInfoMessage(Resources.MeshPrecisionInfo);
            DesignScriptEntity.CheckArgsForAsmExtents(new List<double> {
                height
            });
            height /= DesignScriptEntity.scaleFactor;
            return Wrap(HostFactory.Factory.MeshExtrudePolyCurve(PolyCurve.Unwrap(polycurve), height, Vector.Unwrap(direction), cap), true);
        }
        public List<int> VertexIndicesByTri()
        {
            return MeshEntity.VertexIndicesByTri();
        }
        public Line[] Edges()
        {
            return Line.Wrap(MeshEntity.Edges(), true);
        }
        public Surface[] Triangles()
        {
            return Surface.Wrap(MeshEntity.Triangles(), true);
        }
        public BoundingBox BoundingBox()
        {
            return Autodesk.DesignScript.Geometry.BoundingBox.Wrap(MeshEntity.BoundingBox(), true);
        }
        public Mesh[] Explode()
        {
            return Wrap(MeshEntity.Explode(), true);
        }
        public Vector[] TriangleNormals()
        {
            return Vector.Wrap((from x in (IEnumerable<IVectorEntity>)MeshEntity.TriangleNormals()
            select x.Scale(1 / DesignScriptEntity.scaleFactor)).ToArray(), true);
        }
        public Point[] TriangleCentroids()
        {
            return Point.Wrap(MeshEntity.TriangleCentroids(), true);
        }
        public Mesh BooleanUnion(Mesh tool)
        {
            return Wrap(MeshEntity.BooleanUnion(Unwrap(tool)), true);
        }
        public Mesh BooleanDifference(Mesh tool)
        {
            return Wrap(MeshEntity.BooleanDifference(Unwrap(tool)), true);
        }
        public Mesh BooleanIntersection(Mesh tool)
        {
            return Wrap(MeshEntity.BooleanIntersection(Unwrap(tool)), true);
        }
        public Mesh Repair()
        {
            return Wrap(MeshEntity.Repair(), true);
        }
        public Mesh CloseCracks()
        {
            return Wrap(MeshEntity.CloseCracks(), true);
        }
        public Mesh MakeWatertight()
        {
            return Wrap(MeshEntity.MakeWatertight(), true);
        }
        public Mesh MakeHollow(int holeCount = 1, double holeRadius = 1.5, double wallThickness = 2, double solidResolution = 128, double meshResolution = 128)
        {
            return Wrap(MeshEntity.MakeHollow(holeCount, holeRadius, wallThickness, solidResolution, meshResolution), true);
        }
        public Mesh GenerateSupport(double baseHeight = 0.4, double baseDiameter = 8, double postDiameter = 3, double tipHeight = 1, double tipDiameter = 0.5)
        {
            return Wrap(MeshEntity.GenerateSupport(baseHeight, baseDiameter, postDiameter, tipHeight, tipDiameter), true);
        }
        public Mesh Reduce(double triangleCount)
        {
            return Wrap(MeshEntity.Reduce(triangleCount), true);
        }
        public Mesh Remesh()
        {
            return Wrap(MeshEntity.Remesh(), true);
        }
        public Mesh Smooth(double scale = 4)
        {
            return Wrap(MeshEntity.Smooth(scale), true);
        }
        public Mesh PlaneCut(Plane plane, bool makeSolid = false)
        {
            return Wrap(MeshEntity.PlaneCut(Autodesk.DesignScript.Geometry.Plane.Unwrap(plane), makeSolid), true);
        }
        public PolyCurve[] Intersect(Plane intersectionPlane)
        {
            return PolyCurve.Wrap(MeshEntity.Intersect(Autodesk.DesignScript.Geometry.Plane.Unwrap(intersectionPlane)), true);
        }
        public Point Project(Point point, Vector dir)
        {
            return Point.Wrap(MeshEntity.Project(Point.Unwrap(point), Vector.Unwrap(dir)), true);
        }
        public Point Nearest(Point point)
        {
            return Point.Wrap(MeshEntity.Nearest(Point.Unwrap(point)), true);
        }
        public Mesh Mirror(Plane mirrorPlane)
        {
            return Wrap(MeshEntity.Mirror(Autodesk.DesignScript.Geometry.Plane.Unwrap(mirrorPlane)), true);
        }
        public Mesh Rotate(Vector axis, double degrees = 0)
        {
            return Wrap(MeshEntity.Rotate(Vector.Unwrap(axis), degrees), true);
        }
        public Mesh Scale(double scaleFactor = 1)
        {
            return Wrap(MeshEntity.Scale(scaleFactor), true);
        }
        public Mesh Scale(double x = 1, double y = 1, double z = 1)
        {
            return Wrap(MeshEntity.Scale(x, y, z), true);
        }
        public Mesh Translate(Vector vector)
        {
            return Wrap(MeshEntity.Translate(Vector.Unwrap(vector)), true);
        }
        public Mesh Translate(Vector vector, double distance = 0)
        {
            return Wrap(MeshEntity.Translate(Vector.Unwrap(vector), distance), true);
        }
        public Mesh Translate(double x = 0, double y = 0, double z = 0)
        {
            DesignScriptEntity.CheckArgsForAsmExtents(new List<double> {
                x,
                y,
                z
            });
            x /= DesignScriptEntity.scaleFactor;
            y /= DesignScriptEntity.scaleFactor;
            z /= DesignScriptEntity.scaleFactor;
            return Wrap(MeshEntity.Translate(x, y, z), true);
        }
        [SupressImportIntoVM]
        public static Mesh FromJson(string json)
        {
            return Wrap(HostFactory.Factory.MeshFromJson(json, DesignScriptEntity.scaleFactor), true);
        }
        [SupressImportIntoVM]
        public string ToJson()
        {
            return MeshEntity.MeshToJson(DesignScriptEntity.scaleFactor);
        }
    }
}
            