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

namespace VisiMath.Geometry
{
    /// <summary>
    /// Abstract base for all geometry
    /// </summary>
    public abstract class BaseGeometry : IGeometry
    {
        /// <summary>
        /// Protected base constructor
        /// </summary>
        protected BaseGeometry()
        {
        }

        /// <summary>
        /// XML reader constructor
        /// </summary>
        /// <param name="reader">XML reader</param>
        public BaseGeometry(System.Xml.XmlReader reader)
        {
            ReadXml(reader);    
        }


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

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

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

        #region Distance

        /// <summary>
        /// For generic geometry returns distance from the center of the object
        /// </summary>
        /// <param name="pos"></param>
        /// <returns>Distance</returns>
        public float Distance(Vector3 pos)
        {
            return Distance(ref pos);
        }

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

        /// <summary>
        /// Returns closest distance from the specified point to object
        /// </summary>
        /// <param name="point">position</param>
        /// <returns>Closest distance to the object</returns>
        public float Distance(Point3D point)
        {
            return Distance(point.GetPosition(0));
        }


        /// <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>
        public float Distance(Point3DList pl, int index)
        {
            return Distance(pl.GetPosition(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>
        public float Distance(IVertexArray varray, int index)
        {
            return Distance(varray[index].Position);
        }


        /// <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>
        public float DistancePoints(Point3DList pl, int startindex = 0, int count = 0)
        {
            return DistancePoints(pl.Vertices, startindex, count);
        }

        /// <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>
        public virtual float DistancePoints(IVertexArray varray, int startindex = 0, int count = 0)
        {
            if (count == 0)
                count = varray.Count - startindex;

            float maxdst = float.MaxValue;

            for (int i = startindex; i < count; i++)
            {
                float newd = Distance(varray.Positions[i]);
                if (newd == 0)
                    return 0;
                if (newd < maxdst)
                    maxdst = newd;
            }
            return maxdst;
        }


        /// <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>
        public virtual float Distance(Ray ray, bool frontOnly = false)
        {
            return ray.Distance(Center);
        }


        /// <summary>
        /// Returns closest distance to the line segment
        /// </summary>
        /// <param name="line">Line segment</param>
        /// <returns>Closest distance</returns>
        public float DistanceLineSegment(LineSegment3D line)
        {
            return DistanceLineSegment(line.GetPosition(0), line.GetPosition(1));
        }

        /// <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>
        public float DistanceLineSegment(LineList lines, int index)
        {
            return DistanceLineSegment(lines.GetPosition(index*2), lines.GetPosition(index*2+1));
        }
        /// <summary>
        /// Returns closest distance to the line segment
        /// </summary>
        ///<param name="pos1">Start of the line</param>
        ///<param name="pos2">end of the line</param>
        /// <returns>Closest distance</returns>
        public float DistanceLineSegment(Vector3 pos1, Vector3 pos2)
        {
            return DistanceLineSegment(ref pos1, ref pos2);
        }
        
        /// <summary>
        /// Returns closest distance to the line segment. Generic, from center, OVERRIDE!
        /// </summary>
        ///<param name="pos1">Start of the line</param>
        ///<param name="pos2">end of the line</param>
        /// <returns>Closest distance</returns>
        public virtual float DistanceLineSegment(ref Vector3 pos1, ref Vector3 pos2)
        {
            Vector3 v = Center;
            return MathTools.DistanceVectorLineSegment(ref pos1, ref pos2, ref v);
        }


        /// <summary>
        /// Returns distance from the list of the lines
        /// </summary>
        /// <param name="lines">List of the lines</param>
        /// <param name="startindex">Starting index of the lines</param>
        /// <param name="count">Number of lines to check</param>
        /// <returns>Closest distance</returns>
        protected float DistanceLines(Geometry lines, int startindex, int count)
        {
            float maxd = float.MaxValue;

            for (int i = startindex; i < count; i++)
            {
                float newd = DistanceLineSegment(lines.GetPosition(i * 2), lines.GetPosition(i * 2 + 1));
                if (newd < maxd)
                    maxd = newd;
            }
            return maxd;
        }

        /// <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>        
        public float DistanceLines(LineList lines, int startindex = 0, int count = 0)
        {
            if (count == 0)
                count = lines.Count - startindex;
            return DistanceLines((Geometry)lines, startindex, count);
        }

        /// <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>        
        public float DistanceLines(IndexedLines lines, int startindex = 0, int count = 0)
        {
            if (count == 0)
                count = lines.Count - startindex;
            return DistanceLines((Geometry)lines, startindex, count);
        }


        /// <summary>
        /// Returns closest distance to the triangle
        /// </summary>
        /// <param name="tr">Triangle</param>
        /// <returns>Distance</returns>
        public float DistanceTriangle(Triangle tr)
        {
            return DistanceTriangle(tr.GetPosition(0), tr.GetPosition(1), tr.GetPosition(2));
        }

        /// <summary>
        /// Returns closest distance to the triangle
        /// </summary>
        /// <param name="tr">TriangleList</param>
        /// <param name="index">Index of the triangle</param>
        /// <returns>Distance</returns>
        public float DistanceTriangle(TriangleList tr, int index)
        {
            return DistanceTriangle(tr.GetPosition(index * 3 + 0), tr.GetPosition(index * 3 + 1), tr.GetPosition(index * 3 + 2));
        }

        /// <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>
        public float DistanceTriangle(IndexedMesh im, int index)
        {
            return DistanceTriangle(im.GetPosition(index * 3 + 0), im.GetPosition(index * 3 + 1), im.GetPosition(index * 3 + 2));
        }
        /// <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>
        public float DistanceTriangle(Vector3 pos1, Vector3 pos2, Vector3 pos3)
        {
            return DistanceTriangle(ref pos1, ref pos2, ref pos3);
        }

        /// <summary>
        /// Returns closest distance to the triangle. GENERIC with center, override!!!
        /// </summary>
        /// <param name="pos1">First corner</param>
        /// <param name="pos2">Second corner</param>
        /// <param name="pos3">Third corner</param>
        /// <returns>Distance</returns>
        public virtual float DistanceTriangle(ref Vector3 pos1, ref Vector3 pos2, ref Vector3 pos3)
        {
            Vector3 cen = Center;
            return MathTools.DistanceVectorTriangle(ref pos1, ref pos2, ref pos3, ref cen);
        }


        /// <summary>
        /// Returns distance to triangles
        /// </summary>
        /// <param name="geo">Geometry with triangle data</param>
        /// <param name="startindex">Starting index</param>
        /// <param name="count">Number of triangles to check</param>
        /// <returns>Closest distance</returns>
        protected float DistanceTriangles(Geometry geo, int startindex, int count)
        {
            float maxd = float.MaxValue;
            for (int i = startindex; i < count; i++)
            {
                float newd = DistanceTriangle(geo.GetPosition(i * 3), geo.GetPosition(i * 3 + 1), geo.GetPosition(i * 3 + 1));
                if (newd < maxd)
                    maxd = newd;
            }
            return maxd;
        }

        /// <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>        
        public float DistanceTriangles(TriangleList tlist, int startindex = 0, int count = 0)
        {
            if (count == 0)
                count = tlist.Count - startindex;
            return DistanceTriangles(tlist, startindex, count);
        }

        /// <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>        
        public float DistanceTriangles(IndexedMesh im, int startindex = 0, int count = 0)
        {
            if (count == 0)
                count = im.Count - startindex;
            return DistanceTriangles(im, startindex, count);
        }

        /// <summary>
        /// Returns closest distance to the quad
        /// </summary>
        /// <param name="q">Quad</param>
        /// <returns>Closest distance</returns>        
        public float DistanceQuad(Quad q)
        {
            return DistanceQuad(q.GetPosition(0), q.GetPosition(1), q.GetPosition(2), q.GetPosition(3));
        }
        /// <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>        
        public float DistanceQuad(Vector3 p1, Vector3 p2, Vector3 p3, Vector3 p4)
        {
            return DistanceQuad(ref p1, ref p2, ref p3, ref p4);
        }

        /// <summary>
        /// Returns closest distance to the quad - calls distance from triangle
        /// </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>        
        public virtual float DistanceQuad(ref Vector3 p1, ref Vector3 p2, ref Vector3 p3, ref Vector3 p4)
        {
            float dst1 = DistanceTriangle(ref p1, ref p2, ref p3);
            float dst2 = DistanceTriangle(ref p3, ref p4, ref p1);
            return (dst1<dst2)?dst1:dst2;
        }
        /// <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>        
        public float DistanceQuad(QuadList ql, int index)
        {
            return DistanceQuad(ql.GetPosition(index * 4), ql.GetPosition(index * 4 + 1), ql.GetPosition(index * 4 + 2), ql.GetPosition(index * 4 + 3));
        }
        /// <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>        
        public float DistanceQuad(IndexedQuads ql, int index)
        {
            return DistanceQuad(ql.GetPosition(index * 4), ql.GetPosition(index * 4 + 1), ql.GetPosition(index * 4 + 2), ql.GetPosition(index * 4 + 3));
        }


        /// <summary>
        /// Distance to the list of quads
        /// </summary>
        /// <param name="ql">Geometry holding quads</param>
        /// <param name="startindex">first quad to check</param>
        /// <param name="count">Number of quads to check</param>
        /// <returns>Closest distance</returns>
        public float DistanceQuads(Geometry ql, int startindex, int count)
        {
            float maxd = float.MaxValue;

            for (int index = startindex; index < count; index++)
            {
                float newv = DistanceQuad(ql.GetPosition(index * 4), ql.GetPosition(index * 4 + 1), ql.GetPosition(index * 4 + 2), ql.GetPosition(index * 4 + 3));
                if (newv < maxd)
                    maxd = newv;
            }
            return maxd;
        }

        /// <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>        
        public float DistanceQuads(QuadList ql, int startindex = 0, int count = 0)
        {
            if (count == 0)
                count = ql.Count - startindex;
            return DistanceQuads(ql, startindex, count);
        }

        /// <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>        
        public float DistanceQuads(IndexedQuads ql, int startindex = 0, int count = 0)
        {
                if (count == 0)
                    count = ql.Count - startindex;
                return DistanceQuads(ql, startindex, count);
        }

        /// <summary>
        /// Returns closest distance to the sphere
        /// </summary>
        /// <param name="sph">Sphere object</param>
        /// <returns>Closest distance</returns>
        public virtual float DistanceSphere(Sphere sph)
        {
            return DistanceSphere(sph._Center, sph.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>
        public float DistanceSphere(Vector3 center, float radius)
        {
            return DistanceSphere(ref center, radius);
        }
        /// <summary>
        /// Returns closest distance to the sphere. Used distance to sphere center
        /// </summary>
        /// <param name="center">center of the sphere</param>
        /// <param name="radius">radius of the sphere</param>
        /// <returns>Closest distance</returns>
        public virtual float DistanceSphere(ref Vector3 center, float radius)
        {
            float dst = Distance(ref center) - radius;
            MathTools.ClampMin(ref dst, 0);
            return dst;
        }


        /// <summary>
        /// Returns closest distance from the generic geometric object.
        /// Very generic version, returns distance from centers of objects, should be overriden
        /// </summary>
        /// <param name="obj">Object to check distance with</param>
        /// <returns>Closest distance to the object</returns>
        public virtual float Distance(IGeometry obj)
        {
            Vector3 pos = obj.Center;
            return Center.Distance(ref pos);
        }


        #endregion

        /// <summary>
        /// Checks for intersection between object and ray
        /// </summary>
        /// <param name="ray"></param>
        /// <returns>True if ray intersects the object</returns>
        public virtual bool Intersects(Ray ray)
        {
            IIntersectionInfo inf = IntersectionInfo.CreateNew();

            if (GetIntersectionInfo(ray, ref inf))
                return true;
            return false;
        }

        /// <summary>
        /// Checks for intersection with generic geo object. Very generic, overload.
        /// </summary>
        /// <param name="obj">Object to check with</param>
        /// <returns>True if intersection exists</returns>
        public virtual bool Intersects(IGeometry obj)
        {
            Vector3 v = IntersectionPoint(obj);
            return v.IsValid();
        }

        /// <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>
        public abstract bool ContainsPosition(Vector3 pos);


        /// <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>
        public virtual float IntersectionDistance(Ray ray)
        {
            IIntersectionInfo inf = IntersectionInfo.CreateNew();

            GetIntersectionInfo(ray, ref inf);
            return inf.Distance;
        }

        /// <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>
        public virtual Vector3 IntersectionPoint(Ray ray)
        {
            IIntersectionInfo inf = IntersectionInfo.CreateNew();
            if (GetIntersectionInfo(ray, ref inf))
                return inf.IntersectionPoint;
            else return new Vector3(float.NaN);
        }

        /// <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>
        public virtual Vector3 IntersectionPoint(IGeometry obj)
        {
            return Vector3.Invalid; //do later
        }


        /// <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>
        public abstract 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>        
        public virtual bool GetIntersectionInfo(Ray obj, IntersectionList ilist)
        {
            IIntersectionInfo inf = IntersectionInfo.CreateNew();
            if (GetIntersectionInfo(obj, ref inf))
            {
                ilist.Add(inf);
                return true;
            }
            else return false;
        }

        /// <summary>
        /// Checks for intersection between object and sphere
        /// </summary>
        /// <param name="sph">Sphere object</param>
        /// <returns>True if sphere intersects the object</returns>
        /// <remarks>Uses DistanceSphere</remarks>
        public virtual bool Intersects(Sphere sph)
        {
            if (DistanceSphere(ref sph._Center, sph.Radius) == 0)
                return true;
            return false;
        }

        /// <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 (should start at the center of the sphere!</param>
        /// <returns>Distance to the intersection or -1 if no intersection exists</returns>
        public virtual float IntersectsMoving(Sphere sph, Ray ray, float maxdistance)
        {
            return IntersectsMoving(sph.Radius, ray, 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>
        public abstract float IntersectsMoving(float radius, Ray ray, float maxdistance);


        #region Conversions

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

        /// <summary>
        /// Preferred vertex type for default conversion
        /// </summary>
        public abstract 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>
        public IGeometry ConvertToPrimitive(PrimitiveTypes primType, float quality = 0, int vertexlimit = 0)
        {
            return ConvertToPrimitive(PreferredVertexType, primType, quality, vertexlimit);
        }


        /// <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>
        public IGeometry ConvertToPrimitive<VertexT>(PrimitiveTypes primType, float quality = 0, int vertexlimit = 0)
            where VertexT : IVertex
        {
            return ConvertToPrimitive(typeof(VertexT), primType, quality, vertexlimit);
        }


        /// <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>
        public virtual IGeometry ConvertToPrimitive(Type vertextype, PrimitiveTypes primType, float quality = 0, int vertexlimit = 0)
        {
            switch (primType)
            {
                case PrimitiveTypes.IndexedTriangles:
                    return (IGeometry)ToIndexedMesh(vertextype, quality, vertexlimit);
                case PrimitiveTypes.LineList:
                    return (IGeometry)ToLines(vertextype, quality, vertexlimit);
                case PrimitiveTypes.PointList:
                    return (IGeometry)ToPoints(vertextype, quality, vertexlimit);
                case PrimitiveTypes.TriangleList:
                    return (IGeometry)ToTriangles(vertextype, quality, vertexlimit);
                default:
                    return null;
            }
        }


        /// <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>
        public Point3DList ToPoints(float quality = 0, int vertexlimit = 0)
        {
            return ToPoints(PreferredVertexType, quality, vertexlimit);
        }


        /// <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>
        public Point3DList ToPoints<VertexT>(float quality = 0, int vertexlimit = 0)
            where VertexT : IVertex
        {
            return ToPoints(typeof(VertexT), quality, vertexlimit);
        }

        /// <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>
        public abstract 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>
        public LineList ToLines(float quality = 0, int vertexlimit = 0)
        {
            return ToLines(PreferredVertexType, quality, vertexlimit);
        }

        /// <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>
        public LineList ToLines<VertexT>(float quality = 0, int vertexlimit = 0)
            where VertexT : IVertex
        {
            return ToLines(typeof(VertexT), quality, vertexlimit);
        }
        

        /// <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>
        public abstract 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>
        public TriangleList ToTriangles(float quality = 0, int vertexlimit = 0)            
        {
            return ToTriangles(PreferredVertexType, quality, vertexlimit);
        }

        /// <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>
        public TriangleList ToTriangles<VertexT>(float quality = 0, int vertexlimit = 0)
            where VertexT : IVertex
        {
            return ToTriangles(typeof(VertexT), quality, vertexlimit);
        }

        /// <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>
        public abstract 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>
        public IndexedMesh ToIndexedMesh(float quality = 0, int vertexlimit = 0)
        {
            return ToIndexedMesh(PreferredVertexType, quality, vertexlimit);
        }


        /// <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>
        public IndexedMesh ToIndexedMesh<VertexT>(float quality = 0, int vertexlimit = 0)
            where VertexT : IVertex
        {
            return ToIndexedMesh(typeof(VertexT), quality, vertexlimit);
        }

        /// <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>
        public abstract IndexedMesh ToIndexedMesh(Type vertextype, float quality = 0, int vertexlimit = 0);

        #endregion

        #region IXmlSerializable Members

        /// <summary>
        /// Reqired by IXMLserializable
        /// </summary>
        /// <returns>Null</returns>
        /// <summary>
        /// Reqired by IXMLserializable
        /// </summary>
        /// <returns>Null</returns>
        public System.Xml.Schema.XmlSchema GetSchema()
        {
            return null;
        }

        /// <summary>
        /// Deserializes object from XML
        /// </summary>
        /// <param name="reader">XML reader</param>
        public abstract void ReadXml(System.Xml.XmlReader reader);

        /// <summary>
        /// Serializes object to XML
        /// </summary>
        /// <param name="writer">XML writer to save values</param>
        public abstract void WriteXml(System.Xml.XmlWriter writer);

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

        #endregion
    }
}
