using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;

namespace VisiMath.Geometry
{
    #region Enumerations
    /// <summary>
    /// Enumeration of directly rendered primitives
    /// </summary>
    public enum PrimitiveTypes
    {
        /// <summary>
        /// Single point
        /// </summary>
        Point, 
        /// <summary>
        /// List of points
        /// </summary>
        PointList,
        /// <summary>
        /// Ray
        /// </summary>
        Ray, 
        /// <summary>
        /// Inifinite line
        /// </summary>
        Line,
        /// <summary>
        /// Line segment
        /// </summary>
        LineSegment,
        /// <summary>
        /// Polyline (connected line segments)
        /// </summary>
        PolyLine,
        /// <summary>
        /// List of lines
        /// </summary>
        LineList,
        /// <summary>
        /// Triangle
        /// </summary>
        Triangle,
        /// <summary>
        /// Quad
        /// </summary>
        Quad,
        /// <summary>
        /// List of triangles
        /// </summary>
        TriangleList,
        /// <summary>
        /// List of quads
        /// </summary>
        QuadList,
        /// <summary>
        /// Mesh made from indexed triangles
        /// </summary>
        IndexedTriangles,
        /// <summary>
        /// Mesh made from indexed quads
        /// </summary>
        IndexedQuads,
        /// <summary>
        /// Set of indexed lines
        /// </summary>
        IndexedLines
    };

    /// <summary>
    /// Enumeration of basic bounding objects
    /// </summary>
    public enum BoundingTypes
    {
        Sphere,
        Box,
        Container
    };


    #endregion



    /// <summary>
    /// Generic interface for geometric objects. For XML support IGeometry object MUST provide constructor with XMLReader parameter!!!
    /// </summary>
    public interface IGeometry : IXmlSerializable
    {

        /// <summary>
        /// Is object geometric renderable primitive from enumaration PrimitiveTypes?
        /// </summary>
        bool IsPrimitive { get; }

        /// <summary>
        /// If geometry object is container, it's made of several joined objects
        /// </summary>
        /// <returns>True if container</returns>
        bool IsContainer { get; }

        /// <summary>
        /// Center of the object
        /// </summary>
        Vector3 Center { get; }

        /// <summary>
        /// Returns copy of the geometric data
        /// </summary>
        /// <returns>Full copy of the geometry</returns>
        IGeometry GetCopy();


        #region Distance

        /// <summary>
        /// Returns closest distance from the specified point to object
        /// </summary>
        /// <param name="pos">position</param>
        /// <returns>Closest distance to the object</returns>
        float Distance(Vector3 pos);

        /// <summary>
        /// Returns closest distance from the specified point to object
        /// </summary>
        /// <param name="pos">position</param>
        /// <returns>Closest distance to the object</returns>
        float Distance(ref Vector3 pos);

        /// <summary>
        /// Returns closest distance from the specified point to object
        /// </summary>
        /// <param name="point">position</param>
        /// <returns>Closest distance to the object</returns>
        float Distance(Point3D point);
        
        /// <summary>
        /// Returns closest distance from the specified point to object
        /// </summary>
        /// <param name="pl">Point list</param>
        /// <param name="index">Index of the point</param>
        /// <returns>Closest distance to the object</returns>
        float Distance(Point3DList pl, int index);
        /// <summary>
        /// Returns closest distance from the specified point to object
        /// </summary>
        /// <param name="varray">vertex array</param>
        /// <param name="index">index of the point</param>
        /// <returns>Closest distance to the object</returns>
        float Distance(IVertexArray varray, int index);
        /// <summary>
        /// Returns closest distance from the set of points
        /// </summary>
        /// <param name="pl">point list</param>
        /// <param name="startindex">Starting index of points to check</param>
        /// <param name="count">Number of elements to check (0 = all)</param>
        /// <returns>Closest distance to the object</returns>
        float DistancePoints(Point3DList pl, int startindex = 0, int count = 0);
        /// <summary>
        /// Returns closest distance from the set of points
        /// </summary>
        /// <param name="varray">Vertex array</param>
        /// <param name="startindex">Starting index of points to check</param>
        /// <param name="count">Number of elements to check (0 = all)</param>
        /// <returns>Closest distance to the object</returns>
        float DistancePoints(IVertexArray varray, int startindex = 0, int count = 0);

        /// <summary>
        /// Returns closest distance to the ray
        /// </summary>
        /// <param name="ray">Ray to check distance to</param>
        /// <param name="frontOnly">Check only objects in front of the origin</param>
        /// <returns>Closest distance to the ray, if frontOnly and object is behind the ray, returns NaN</returns>
        float Distance(Ray ray, bool frontOnly = false);

        /// <summary>
        /// Returns closest distance to the line segment
        /// </summary>
        /// <param name="line">Line segment</param>
        /// <returns>Closest distance</returns>
        float DistanceLineSegment(LineSegment3D line);
        /// <summary>
        /// Returns closest distance to the line segment
        /// </summary>
        /// <param name="lines">Line list</param>
        /// <param name="index">Index of the line in the list</param>
        /// <returns>Closest distance</returns>
        float DistanceLineSegment(LineList lines, int index);
        /// <summary>
        /// Returns closest distance to the line segment
        /// </summary>
        /// <param name="pos1">Start of line segment</param>
        /// <param name="pos2">End of line segment</param>
        /// <returns>Closest distance</returns>
        float DistanceLineSegment(Vector3 pos1, Vector3 pos2);
        /// <summary>
        /// Returns closest distance to the line segment
        /// </summary>
        /// <param name="pos1">Start of the segment</param>
        /// <param name="pos2">End of the segment</param>
        /// <returns>Closest distance</returns>
        float DistanceLineSegment(ref Vector3 pos1, ref Vector3 pos2);
        /// <summary>
        /// Returns closest distance to any of the lines from the set
        /// </summary>
        /// <param name="lines">List of lines</param>
        /// <param name="startindex">Starting index of points to check</param>
        /// <param name="count">Number of elements to check (0 = all)</param>
        /// <returns>Closest distance</returns>        
        float DistanceLines(LineList lines, int startindex = 0, int count = 0);
        /// <summary>
        /// Returns closest distance to any of the lines from the set
        /// </summary>
        /// <param name="lines">Indexed list of lines</param>
        /// <param name="startindex">Starting index of points to check</param>
        /// <param name="count">Number of elements to check (0 = all)</param>
        /// <returns>Closest distance</returns>        
        float DistanceLines(IndexedLines lines, int startindex = 0, int count = 0);


        /// <summary>
        /// Returns closest distance to the triangle
        /// </summary>
        /// <param name="tr">Triangle</param>
        /// <returns>Distance</returns>
        float DistanceTriangle(Triangle tr);
        /// <summary>
        /// Returns closest distance to the triangle
        /// </summary>
        /// <param name="tr">TriangleList</param>
        /// <param name="index">Index of the triangle</param>
        /// <returns>Distance</returns>
        float DistanceTriangle(TriangleList tr, int index);
        /// <summary>
        /// Returns closest distance to the triangle
        /// </summary>
        /// <param name="im">Indexed triangle list</param>
        /// <param name="index">Index of the triangle</param>
        /// <returns>Distance</returns>
        float DistanceTriangle(IndexedMesh im, int index);
        /// <summary>
        /// Returns closest distance to the triangle
        /// </summary>
        /// <param name="pos1">First corner</param>
        /// <param name="pos2">Second corner</param>
        /// <param name="pos3">Third corner</param>
        /// <returns>Distance</returns>
        float DistanceTriangle(Vector3 pos1, Vector3 pos2, Vector3 pos3);
        /// <summary>
        /// Returns closest distance to the triangle
        /// </summary>
        /// <param name="pos1">First corner</param>
        /// <param name="pos2">Second corner</param>
        /// <param name="pos3">Third corner</param>
        /// <returns>Distance</returns>
        float DistanceTriangle(ref Vector3 pos1, ref Vector3 pos2, ref Vector3 pos3);
        /// <summary>
        /// Returns closest distance to the set of triangles
        /// </summary>
        /// <param name="tlist">Set of triangles</param>
        /// <param name="startindex">Starting index of points to check</param>
        /// <param name="count">Number of elements to check (0 = all)</param>
        /// <returns>Closest distance</returns>        
        float DistanceTriangles(TriangleList tlist, int startindex = 0, int count = 0);
        /// <summary>
        /// Returns closest distance to the set of triangles
        /// </summary>
        /// <param name="im">Set of triangles</param>
        /// <param name="startindex">Starting index of points to check</param>
        /// <param name="count">Number of elements to check (0 = all)</param>
        /// <returns>Closest distance</returns>        
        float DistanceTriangles(IndexedMesh im, int startindex = 0, int count = 0);

        /// <summary>
        /// Returns closest distance to the quad
        /// </summary>
        /// <param name="q">Quad</param>
        /// <returns>Closest distance</returns>        
        float DistanceQuad(Quad q);
        /// <summary>
        /// Returns closest distance to the quad
        /// </summary>
        /// <param name="p1">quad corner</param>
        /// <param name="p2">quad corner</param>
        /// <param name="p3">quad corner</param>
        /// <param name="p4">quad corner></param>
        /// <returns>Closest distance</returns>        
        float DistanceQuad(Vector3 p1, Vector3 p2, Vector3 p3, Vector3 p4);
        /// <summary>
        /// Returns closest distance to the quad
        /// </summary>
        /// <param name="p1">quad corner</param>
        /// <param name="p2">quad corner</param>
        /// <param name="p3">quad corner</param>
        /// <param name="p4">quad corner></param>
        /// <returns>Closest distance</returns>        
        float DistanceQuad(ref Vector3 p1, ref Vector3 p2, ref Vector3 p3, ref Vector3 p4);
        /// <summary>
        /// Returns closest distance to the quad
        /// </summary>
        /// <param name="ql">List of quads</param>
        /// <param name="index">index of the quad</param>
        /// <returns>Closest distance</returns>        
        float DistanceQuad(QuadList ql, int index);
        /// <summary>
        /// Returns closest distance to the quad
        /// </summary>
        /// <param name="ql">List of quads</param>
        /// <param name="index">index of the quad</param>
        /// <returns>Closest distance</returns>        
        float DistanceQuad(IndexedQuads ql, int index);

        /// <summary>
        /// Returns closest distance to the set of quads
        /// </summary>
        /// <param name="ql">Set of quads</param>
        /// <param name="startindex">Starting index of points to check</param>
        /// <param name="count">Number of elements to check (0 = all)</param>
        /// <returns>Closest distance</returns>        
        float DistanceQuads(QuadList ql, int startindex = 0, int count = 0);
        /// <summary>
        /// Returns closest distance to the set of quads
        /// </summary>
        /// <param name="ql">Set of quads</param>
        /// <param name="startindex">Starting index of points to check</param>
        /// <param name="count">Number of elements to check (0 = all)</param>
        /// <returns>Closest distance</returns>        
        float DistanceQuads(IndexedQuads ql, int startindex = 0, int count = 0);

        /// <summary>
        /// Returns closest distance to the sphere
        /// </summary>
        /// <param name="sph">Sphere object</param>
        /// <returns>Closest distance</returns>
        float DistanceSphere(Sphere sph);
        /// <summary>
        /// Returns closest distance to the sphere
        /// </summary>
        /// <param name="center">center of the sphere</param>
        /// <param name="radius">radius of the sphere</param>
        /// <returns>Closest distance</returns>
        float DistanceSphere(Vector3 center, float radius);
        /// <summary>
        /// Returns closest distance to the sphere
        /// </summary>
        /// <param name="center">center of the sphere</param>
        /// <param name="radius">radius of the sphere</param>
        /// <returns>Closest distance</returns>
        float DistanceSphere(ref Vector3 center, float radius);

        /// <summary>
        /// Returns closest distance from the generic geometric object
        /// </summary>
        /// <param name="obj">Object to check distance with</param>
        /// <returns>Closest distance to the object</returns>
        float Distance(IGeometry obj);

        #endregion

        #region Intersections

        /// <summary>
        /// Checks if specified position is inside the object
        /// </summary>
        /// <param name="pos">Position to check</param>
        /// <returns>True if vector is inside the object</returns>
        bool ContainsPosition(Vector3 pos);

        /// <summary>
        /// Checks for intersection with generic geo object
        /// </summary>
        /// <param name="obj">Object to check with</param>
        /// <returns>True if intersection exists</returns>
        bool Intersects(IGeometry obj);

        /// <summary>
        /// Checks for intersection between object and ray
        /// </summary>
        /// <param name="ray"></param>
        /// <returns>True if ray intersects the object</returns>
        bool Intersects(Ray ray);

        /// <summary>
        /// Returns distance to the intersection between object and ray
        /// </summary>
        /// <param name="ray"></param>
        /// <returns>Distance from the origin to the point of intersection or double.NaN if no intersection</returns>
        float IntersectionDistance(Ray ray);

        /// <summary>
        /// Returns closest point of the intersection between object and ray
        /// </summary>
        /// <param name="ray"></param>
        /// <returns>Point of intersection or invalid Vector3 (with double.NaN as values)</returns>
        Vector3 IntersectionPoint(Ray ray);

        /// <summary>
        /// Returns first found point of the intersection bewteen objects
        /// </summary>
        /// <param name="obj">Object to check</param>
        /// <returns>Position of the first found intersection</returns>
        Vector3 IntersectionPoint(IGeometry obj);

        /// <summary>
        /// Check for intersection and fills intersection info if intersection is closer to the origin of the ray then value before
        /// </summary>
        /// <param name="inters">Data structure with intersection info</param>
        /// <param name="obj">Ray object</param>
        /// <returns>True if there was an intersection and it was closer then previous stored</returns>
        bool GetIntersectionInfo(Ray obj, ref IIntersectionInfo inters);

        /// <summary>
        /// Check for intersection and adds intersection info if there was any intersection
        /// </summary>
        /// <param name="ilist">List for intersections</param>
        /// <param name="obj">Ray object</param>
        /// <returns>True if there was an intersection</returns>        
        bool GetIntersectionInfo(Ray obj, IntersectionList ilist);


        /// <summary>
        /// Checks for intersection between object and sphere
        /// </summary>
        /// <param name="sph">Sphere object</param>
        /// <returns>True if sphere intersects the object</returns>
        bool Intersects(Sphere sph);

        /// <summary>
        /// Checks for intersection between object and moving sphere
        /// </summary>
        /// <param name="sph">Sphere object</param>
        /// <param name="maxdistance">Maximal distance to travel</param>
        /// <param name="ray">Ray describing movement of the sphere</param>
        /// <returns>Distance to the intersection or -1 if no intersection exists</returns>
        float IntersectsMoving(Sphere sph, Ray ray, float maxdistance);

        /// <summary>
        /// Checks for intersection between object and moving sphere
        /// </summary>
        ///<param name="radius">Radius of the sphere</param>
        /// <param name="maxdistance">Maximal distance to travel</param>
        /// <param name="ray">Ray describing movement of the sphere</param>
        /// <returns>Distance to the intersection or -1 if no intersection exists</returns>
        float IntersectsMoving(float radius, Ray ray, float maxdistance);


        #endregion

        #region Conversion

        /// <summary>
        /// Preferred primitive type for rendering
        /// </summary>
        PrimitiveTypes PreferredPrimitive { get; }

        /// <summary>
        /// Preferred vertex type for default conversion
        /// </summary>
        Type PreferredVertexType { get; }

        /// <summary>
        /// Converts object to new geometry object with specified primitive type and optionally with quality parameters
        /// </summary>
        /// <param name="primType">Specified type of the primitive</param>
        /// <param name="quality">
        /// Quality for parametric objects (0-1). Zero is simples possible, 1 maximal for the current dimension of the object. 
        /// If vertexlimit parameter is used, quality will be reduced to fullfill maximal vertex budget
        /// </param>
        /// <param name="vertexlimit">Maximal number of allowed vertices. If set to zero, there's no limit. 
        /// Used for fully parametric objects or to reduce number of the vertices in complicated objects.</param>
        /// <returns>New object of specified type</returns>
        IGeometry ConvertToPrimitive(PrimitiveTypes primType, float quality = 0, int vertexlimit = 0);

        /// <summary>
        /// Converts object to new geometry object with specified primitive type and optionally with quality parameters
        /// </summary>
        /// <param name="primType">Specified type of the primitive</param>
        /// <param name="quality">
        /// Quality for parametric objects (0-1). Zero is simples possible, 1 maximal for the current dimension of the object. 
        /// If vertexlimit parameter is used, quality will be reduced to fullfill maximal vertex budget
        /// </param>
        /// <param name="vertexlimit">Maximal number of allowed vertices. If set to zero, there's no limit. 
        /// Used for fully parametric objects or to reduce number of the vertices in complicated objects.</param>
        /// <typeparam name="VertexT">Required Vertex type</typeparam>
        /// <returns>New object of specified type</returns>
        IGeometry ConvertToPrimitive<VertexT>(PrimitiveTypes primType, float quality = 0, int vertexlimit = 0)
            where VertexT : IVertex;

        /// <summary>
        /// Converts object to new geometry object with specified primitive type and optionally with quality parameters
        /// </summary>
        /// <param name="primType">Specified type of the primitive</param>
        /// <param name="quality">
        /// Quality for parametric objects (0-1). Zero is simples possible, 1 maximal for the current dimension of the object. 
        /// If vertexlimit parameter is used, quality will be reduced to fullfill maximal vertex budget
        /// </param>
        /// <param name="vertexlimit">Maximal number of allowed vertices. If set to zero, there's no limit. 
        /// Used for fully parametric objects or to reduce number of the vertices in complicated objects.</param>
        /// <param name="vertextype">Required type of the vertex</param>
        /// <returns>New object of specified type</returns>
        IGeometry ConvertToPrimitive(Type vertextype, PrimitiveTypes primType, float quality = 0, int vertexlimit = 0);


        /// <summary>
        /// Convert object to list of points
        /// </summary>
        /// <returns>New geometry object containing point based definition of the object</returns>
        /// <param name="quality">
        /// Quality for parametric objects (0-1). Zero is simples possible, 1 maximal for the current dimension of the object. 
        /// If vertexlimit parameter is used, quality will be reduced to fullfill maximal vertex budget
        /// </param>
        /// <param name="vertexlimit">Maximal number of allowed vertices. If set to zero, there's no limit. 
        /// Used for fully parametric objects or to reduce number of the vertices in complicated objects.</param>
        Point3DList ToPoints(float quality = 0, int vertexlimit = 0);

        /// <summary>
        /// Convert object to list of points
        /// </summary>
        /// <returns>New geometry object containing point based definition of the object</returns>
        /// <param name="quality">
        /// Quality for parametric objects (0-1). Zero is simples possible, 1 maximal for the current dimension of the object. 
        /// If vertexlimit parameter is used, quality will be reduced to fullfill maximal vertex budget
        /// </param>
        /// <typeparam name="VertexT">Required Vertex type</typeparam>
        /// <param name="vertexlimit">Maximal number of allowed vertices. If set to zero, there's no limit. 
        /// Used for fully parametric objects or to reduce number of the vertices in complicated objects.</param>
        Point3DList ToPoints<VertexT>(float quality = 0, int vertexlimit = 0)
            where VertexT : IVertex;

        /// <summary>
        /// Convert object to list of points
        /// </summary>
        /// <returns>New geometry object containing point based definition of the object</returns>
        /// <param name="quality">
        /// Quality for parametric objects (0-1). Zero is simples possible, 1 maximal for the current dimension of the object. 
        /// If vertexlimit parameter is used, quality will be reduced to fullfill maximal vertex budget
        /// </param>
        /// <param name="vertexlimit">Maximal number of allowed vertices. If set to zero, there's no limit. 
        /// Used for fully parametric objects or to reduce number of the vertices in complicated objects.</param>
        /// <param name="vertextype">Required type of the vertex</param>
        Point3DList ToPoints(Type vertextype, float quality = 0, int vertexlimit = 0);



        /// <summary>
        /// Convert object to list of lines
        /// </summary>
        /// <returns>New geometry object containing edges of the object</returns>
        /// <param name="quality">
        /// Quality for parametric objects (0-1). Zero is simples possible, 1 maximal for the current dimension of the object. 
        /// If vertexlimit parameter is used, quality will be reduced to fullfill maximal vertex budget
        /// </param>
        /// <param name="vertexlimit">Maximal number of allowed vertices. If set to zero, there's no limit. 
        /// Used for fully parametric objects or to reduce number of the vertices in complicated objects.</param>
        LineList ToLines(float quality = 0, int vertexlimit = 0);

        /// <summary>
        /// Convert object to list of lines
        /// </summary>
        /// <returns>New geometry object containing edges of the object</returns>
        /// <param name="quality">
        /// Quality for parametric objects (0-1). Zero is simples possible, 1 maximal for the current dimension of the object. 
        /// If vertexlimit parameter is used, quality will be reduced to fullfill maximal vertex budget
        /// </param>
        /// <typeparam name="VertexT">Required Vertex type</typeparam>
        /// <param name="vertexlimit">Maximal number of allowed vertices. If set to zero, there's no limit. 
        /// Used for fully parametric objects or to reduce number of the vertices in complicated objects.</param>
        LineList ToLines<VertexT>(float quality = 0, int vertexlimit = 0)
            where VertexT : IVertex;

        /// <summary>
        /// Convert object to list of lines
        /// </summary>
        /// <returns>New geometry object containing edges of the object</returns>
        /// <param name="quality">
        /// Quality for parametric objects (0-1). Zero is simples possible, 1 maximal for the current dimension of the object. 
        /// If vertexlimit parameter is used, quality will be reduced to fullfill maximal vertex budget
        /// </param>
        /// <param name="vertexlimit">Maximal number of allowed vertices. If set to zero, there's no limit. 
        /// Used for fully parametric objects or to reduce number of the vertices in complicated objects.</param>
        /// <param name="vertextype">Required type of the vertex</param>
        LineList ToLines(Type vertextype, float quality = 0, int vertexlimit = 0);




        /// <summary>
        /// Convert object to list of triangles. Valid only for surface based objects, otherwise returns null.
        /// </summary>
        /// <returns>New geometry object containing triangle faces of the object surface.</returns>
        /// <param name="quality">
        /// Quality for parametric objects (0-1). Zero is simples possible, 1 maximal for the current dimension of the object. 
        /// If vertexlimit parameter is used, quality will be reduced to fullfill maximal vertex budget
        /// </param>
        /// <param name="vertexlimit">Maximal number of allowed vertices. If set to zero, there's no limit. 
        /// Used for fully parametric objects or to reduce number of the vertices in complicated objects.</param>
        TriangleList ToTriangles(float quality = 0, int vertexlimit = 0);

        /// <summary>
        /// Convert object to list of triangles. Valid only for surface based objects, otherwise returns null.
        /// </summary>
        /// <returns>New geometry object containing triangle faces of the object surface.</returns>
        /// <param name="quality">
        /// Quality for parametric objects (0-1). Zero is simples possible, 1 maximal for the current dimension of the object. 
        /// If vertexlimit parameter is used, quality will be reduced to fullfill maximal vertex budget
        /// </param>
        /// <typeparam name="VertexT">Required Vertex type</typeparam>
        /// <param name="vertexlimit">Maximal number of allowed vertices. If set to zero, there's no limit. 
        /// Used for fully parametric objects or to reduce number of the vertices in complicated objects.</param>
        TriangleList ToTriangles<VertexT>(float quality = 0, int vertexlimit = 0)
            where VertexT : IVertex;

        /// <summary>
        /// Convert object to list of triangles. Valid only for surface based objects, otherwise returns null.
        /// </summary>
        /// <returns>New geometry object containing triangle faces of the object surface.</returns>
        /// <param name="quality">
        /// Quality for parametric objects (0-1). Zero is simples possible, 1 maximal for the current dimension of the object. 
        /// If vertexlimit parameter is used, quality will be reduced to fullfill maximal vertex budget
        /// </param>
        /// <param name="vertexlimit">Maximal number of allowed vertices. If set to zero, there's no limit. 
        /// Used for fully parametric objects or to reduce number of the vertices in complicated objects.</param>
        /// <param name="vertextype">Required type of the vertex</param>
        TriangleList ToTriangles(Type vertextype, float quality = 0, int vertexlimit = 0);



        /// <summary>
        /// Convert object to indexed triangle mesh. Valid only for surface based objects, otherwise returns null.
        /// </summary>
        /// <returns>New geometry object containing triangle faces of the object surface</returns>
        /// <param name="quality">
        /// Quality for parametric objects (0-1). Zero is simples possible, 1 maximal for the current dimension of the object. 
        /// If vertexlimit parameter is used, quality will be reduced to fullfill maximal vertex budget
        /// </param>
        /// <param name="vertexlimit">Maximal number of allowed vertices. If set to zero, there's no limit. 
        /// Used for fully parametric objects or to reduce number of the vertices in complicated objects.</param>
        IndexedMesh ToIndexedMesh(float quality = 0, int vertexlimit = 0);

        /// <summary>
        /// Convert object to indexed triangle mesh. Valid only for surface based objects, otherwise returns null.
        /// </summary>
        /// <returns>New geometry object containing triangle faces of the object surface</returns>
        /// <param name="quality">
        /// Quality for parametric objects (0-1). Zero is simples possible, 1 maximal for the current dimension of the object. 
        /// If vertexlimit parameter is used, quality will be reduced to fullfill maximal vertex budget
        /// </param>
        /// <typeparam name="VertexT">Required Vertex type</typeparam>
        /// <param name="vertexlimit">Maximal number of allowed vertices. If set to zero, there's no limit. 
        /// Used for fully parametric objects or to reduce number of the vertices in complicated objects.</param>
        IndexedMesh ToIndexedMesh<VertexT>(float quality = 0, int vertexlimit = 0)
            where VertexT : IVertex;

        /// <summary>
        /// Convert object to indexed triangle mesh. Valid only for surface based objects, otherwise returns null.
        /// </summary>
        /// <returns>New geometry object containing triangle faces of the object surface</returns>
        /// <param name="quality">
        /// Quality for parametric objects (0-1). Zero is simples possible, 1 maximal for the current dimension of the object. 
        /// If vertexlimit parameter is used, quality will be reduced to fullfill maximal vertex budget
        /// </param>
        /// <param name="vertexlimit">Maximal number of allowed vertices. If set to zero, there's no limit. 
        /// Used for fully parametric objects or to reduce number of the vertices in complicated objects.</param>
        /// <param name="vertextype">Required type of the vertex</param>
        IndexedMesh ToIndexedMesh(Type vertextype, float quality = 0, int vertexlimit = 0);

        #endregion



    } //interface IGeometry


    /// <summary>
    /// Surface based geometry
    /// </summary>
    interface ISurfaceGeo
    {
        /// <summary>
        /// Recalculate normals for the surface
        /// </summary>
        void RecalculateNormals();
    }
}
