[
  {
    "path": ".gitattributes",
    "content": "###############################################################################\n# Set default behavior to automatically normalize line endings.\n###############################################################################\n* text=auto\n\n###############################################################################\n# Set default behavior for command prompt diff.\n#\n# This is need for earlier builds of msysgit that does not have it on by\n# default for csharp files.\n# Note: This is only used by command line\n###############################################################################\n#*.cs     diff=csharp\n\n###############################################################################\n# Set the merge driver for project and solution files\n#\n# Merging from the command prompt will add diff markers to the files if there\n# are conflicts (Merging from VS is not affected by the settings below, in VS\n# the diff markers are never inserted). Diff markers may cause the following \n# file extensions to fail to load in VS. An alternative would be to treat\n# these files as binary and thus will always conflict and require user\n# intervention with every merge. To do so, just uncomment the entries below\n###############################################################################\n#*.sln       merge=binary\n#*.csproj    merge=binary\n#*.vbproj    merge=binary\n#*.vcxproj   merge=binary\n#*.vcproj    merge=binary\n#*.dbproj    merge=binary\n#*.fsproj    merge=binary\n#*.lsproj    merge=binary\n#*.wixproj   merge=binary\n#*.modelproj merge=binary\n#*.sqlproj   merge=binary\n#*.wwaproj   merge=binary\n\n###############################################################################\n# behavior for image files\n#\n# image files are treated as binary by default.\n###############################################################################\n#*.jpg   binary\n#*.png   binary\n#*.gif   binary\n\n###############################################################################\n# diff behavior for common document formats\n# \n# Convert binary document formats to text before diffing them. This feature\n# is only available from the command line. Turn it on by uncommenting the \n# entries below.\n###############################################################################\n#*.doc   diff=astextplain\n#*.DOC   diff=astextplain\n#*.docx  diff=astextplain\n#*.DOCX  diff=astextplain\n#*.dot   diff=astextplain\n#*.DOT   diff=astextplain\n#*.pdf   diff=astextplain\n#*.PDF   diff=astextplain\n#*.rtf   diff=astextplain\n#*.RTF   diff=astextplain\n"
  },
  {
    "path": ".gitignore",
    "content": "## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n\n# User-specific files\n*.suo\n*.user\n*.userosscache\n*.sln.docstates\n\n# User-specific files (MonoDevelop/Xamarin Studio)\n*.userprefs\n\n# Build results\n[Dd]ebug/\n[Dd]ebugPublic/\n[Rr]elease/\n[Rr]eleases/\n[Xx]64/\n[Xx]86/\n[Bb]uild/\nbld/\n[Bb]in/\n[Oo]bj/\n\n# Visual Studio 2015 cache/options directory\n.vs/\n# Uncomment if you have tasks that create the project's static files in wwwroot\n#wwwroot/\n\n# MSTest test Results\n[Tt]est[Rr]esult*/\n[Bb]uild[Ll]og.*\n\n# NUNIT\n*.VisualState.xml\nTestResult.xml\n\n# Build Results of an ATL Project\n[Dd]ebugPS/\n[Rr]eleasePS/\ndlldata.c\n\n# DNX\nproject.lock.json\nartifacts/\n\n*_i.c\n*_p.c\n*_i.h\n*.ilk\n*.meta\n*.obj\n*.pch\n*.pdb\n*.pgc\n*.pgd\n*.rsp\n*.sbr\n*.tlb\n*.tli\n*.tlh\n*.tmp\n*.tmp_proj\n*.log\n*.vspscc\n*.vssscc\n.builds\n*.pidb\n*.svclog\n*.scc\n\n# Chutzpah Test files\n_Chutzpah*\n\n# Visual C++ cache files\nipch/\n*.aps\n*.ncb\n*.opendb\n*.opensdf\n*.sdf\n*.cachefile\n*.VC.db\n\n# Visual Studio profiler\n*.psess\n*.vsp\n*.vspx\n*.sap\n\n# TFS 2012 Local Workspace\n$tf/\n\n# Guidance Automation Toolkit\n*.gpState\n\n# ReSharper is a .NET coding add-in\n_ReSharper*/\n*.[Rr]e[Ss]harper\n*.DotSettings.user\n\n# JustCode is a .NET coding add-in\n.JustCode\n\n# TeamCity is a build add-in\n_TeamCity*\n\n# DotCover is a Code Coverage Tool\n*.dotCover\n\n# NCrunch\n_NCrunch_*\n.*crunch*.local.xml\nnCrunchTemp_*\n\n# MightyMoose\n*.mm.*\nAutoTest.Net/\n\n# Web workbench (sass)\n.sass-cache/\n\n# Installshield output folder\n[Ee]xpress/\n\n# DocProject is a documentation generator add-in\nDocProject/buildhelp/\nDocProject/Help/*.HxT\nDocProject/Help/*.HxC\nDocProject/Help/*.hhc\nDocProject/Help/*.hhk\nDocProject/Help/*.hhp\nDocProject/Help/Html2\nDocProject/Help/html\n\n# Click-Once directory\npublish/\n\n# Publish Web Output\n*.[Pp]ublish.xml\n*.azurePubxml\n\n# TODO: Un-comment the next line if you do not want to checkin\n# your web deploy settings because they may include unencrypted\n# passwords\n#*.pubxml\n*.publishproj\n\n# NuGet Packages\n*.nupkg\n# The packages folder can be ignored because of Package Restore\n**/packages/*\n# except build/, which is used as an MSBuild target.\n!**/packages/build/\n# Uncomment if necessary however generally it will be regenerated when needed\n#!**/packages/repositories.config\n# NuGet v3's project.json files produces more ignoreable files\n*.nuget.props\n*.nuget.targets\n\n# Microsoft Azure Build Output\ncsx/\n*.build.csdef\n\n# Microsoft Azure Emulator\necf/\nrcf/\n\n# Windows Store app package directory\nAppPackages/\nBundleArtifacts/\n\n# Visual Studio cache files\n# files ending in .cache can be ignored\n*.[Cc]ache\n# but keep track of directories ending in .cache\n!*.[Cc]ache/\n\n# Others\nClientBin/\n[Ss]tyle[Cc]op.*\n~$*\n*~\n*.dbmdl\n*.dbproj.schemaview\n*.pfx\n*.publishsettings\nnode_modules/\norleans.codegen.cs\n\n# RIA/Silverlight projects\nGenerated_Code/\n\n# Backup & report files from converting an old project file\n# to a newer Visual Studio version. Backup files are not needed,\n# because we have git ;-)\n_UpgradeReport_Files/\nBackup*/\nUpgradeLog*.XML\nUpgradeLog*.htm\n\n# SQL Server files\n*.mdf\n*.ldf\n\n# Business Intelligence projects\n*.rdl.data\n*.bim.layout\n*.bim_*.settings\n\n# Microsoft Fakes\nFakesAssemblies/\n\n# GhostDoc plugin setting file\n*.GhostDoc.xml\n\n# Node.js Tools for Visual Studio\n.ntvs_analysis.dat\n\n# Visual Studio 6 build log\n*.plg\n\n# Visual Studio 6 workspace options file\n*.opt\n\n# Visual Studio LightSwitch build output\n**/*.HTMLClient/GeneratedArtifacts\n**/*.DesktopClient/GeneratedArtifacts\n**/*.DesktopClient/ModelManifest.xml\n**/*.Server/GeneratedArtifacts\n**/*.Server/ModelManifest.xml\n_Pvt_Extensions\n\n# LightSwitch generated files\nGeneratedArtifacts/\nModelManifest.xml\n\n# Paket dependency manager\n.paket/paket.exe\n\n# FAKE - F# Make\n.fake/\n"
  },
  {
    "path": "GeometRi/AABB.cs",
    "content": "﻿using System;\nusing static System.Math;\nusing System.Collections.Generic;\n\nnamespace GeometRi\n{\n    /// <summary>\n    /// Axis aligned 3D box, can be degenerated with one or more dimensions equal 0. Defined only in Global CS.\n    /// </summary>\n#if NET20_OR_GREATER\n    [Serializable]\n#endif\n    public class AABB : FiniteObject, IFiniteObject\n    {\n\n        private Point3d _center;\n        private double _lx, _ly, _lz;\n\n        private List<Point3d> _list_p = null;\n        private List<Triangle> _list_t = null;\n        private List<Segment3d> _list_e = null;\n        private List<Plane3d> _list_plane = null;\n        private static object _lock = new object();\n\n        #region \"Constructors\"\n\n        /// <summary>\n        /// Default constructor, initializes box in the origin of the global coordinate system aligned with coordinate axes.\n        /// </summary>\n        public AABB(Point3d center, double lx, double ly, double lz)\n        {\n            _center = center.ConvertToGlobal().Copy();\n            _lx = lx;\n            _ly = ly;\n            _lz = lz;\n        }\n\n        /// <summary>\n        /// Initializes unit box in the origin of the global coordinate system aligned with coordinate axes.\n        /// </summary>\n        public AABB()\n        {\n            _center = new Point3d();\n            _lx = _ly = _lz = 1.0;\n        }\n\n        /// <summary>\n        /// Initializes axis aligned box by two points.\n        /// </summary>\n        public AABB(Point3d Pmin, Point3d Pmax)\n        {\n            Point3d p1 = Pmin.ConvertToGlobal();\n            Point3d p2 = Pmax.ConvertToGlobal();\n            _center = (p1 + p2) / 2;\n            _lx = Abs(p2.X - p1.X);\n            _ly = Abs(p2.Y - p1.Y);\n            _lz = Abs(p2.Z - p1.Z);\n        }\n\n        #endregion\n\n        /// <summary>\n        /// Creates copy of the object\n        /// </summary>\n        public AABB Copy()\n        {\n            return new AABB(_center, _lx, _ly, _lz);\n        }\n\n        #region \"Properties\"\n        /// <summary>\n        /// Center point of the box.\n        /// </summary>\n        public Point3d Center\n        {\n            get { return _center; }\n            set\n            {\n                _center = value.Copy();\n                _list_p = null;\n                _list_t = null;\n                _list_e = null;\n                _list_plane = null;\n            }\n        }\n\n        /// <summary>\n        /// First dimension.\n        /// </summary>\n        public double L1\n        {\n            get { return _lx; }\n            set\n            {\n                _lx = value;\n                _list_p = null;\n                _list_t = null;\n                _list_e = null;\n                _list_plane = null;\n            }\n        }\n\n        /// <summary>\n        /// Second dimension.\n        /// </summary>\n        public double L2\n        {\n            get { return _ly; }\n            set\n            {\n                _ly = value;\n                _list_p = null;\n                _list_t = null;\n                _list_e = null;\n                _list_plane = null;\n            }\n        }\n\n        /// <summary>\n        /// Third dimension.\n        /// </summary>\n        public double L3\n        {\n            get { return _lz; }\n            set\n            {\n                _lz = value;\n                _list_p = null;\n                _list_t = null;\n                _list_e = null;\n                _list_plane = null;\n            }\n        }\n\n        public double Xmin { get { return _center.X - _lx / 2; } }\n        public double Xmax { get { return _center.X + _lx / 2; } }\n        public double Ymin { get { return _center.Y - _ly / 2; } }\n        public double Ymax { get { return _center.Y + _ly / 2; } }\n        public double Zmin { get { return _center.Z - _lz / 2; } }\n        public double Zmax { get { return _center.Z + _lz / 2; } }\n\n\n        /// <summary>\n        /// Orientation of the first dimension of the box.\n        /// </summary>\n        public Vector3d V1\n        {\n            get { return Coord3d.GlobalCS.Xaxis; }\n        }\n\n        /// <summary>\n        /// Orientation of the second dimension of the box.\n        /// </summary>\n        public Vector3d V2\n        {\n            get { return Coord3d.GlobalCS.Yaxis; }\n        }\n\n        /// <summary>\n        /// Orientation of the third dimension of the box.\n        /// </summary>\n        public Vector3d V3\n        {\n            get { return Coord3d.GlobalCS.Zaxis; }\n        }\n\n\n        /// <summary>\n        /// Corner point of the box.\n        /// </summary>\n        public Point3d P1\n        {\n            get\n            {\n                return new Point3d(_center.X - 0.5 * _lx, _center.Y - 0.5 * _ly, _center.Z - 0.5 * _lz);\n            }\n        }\n\n        /// <summary>\n        /// Corner point of the box.\n        /// </summary>\n        public Point3d P2\n        {\n            get\n            {\n                return new Point3d(_center.X + 0.5 * _lx, _center.Y - 0.5 * _ly, _center.Z - 0.5 * _lz);\n            }\n        }\n\n        /// <summary>\n        /// Corner point of the box.\n        /// </summary>\n        public Point3d P3\n        {\n            get\n            {\n                return new Point3d(_center.X + 0.5 * _lx, _center.Y + 0.5 * _ly, _center.Z - 0.5 * _lz);\n            }\n        }\n\n        /// <summary>\n        /// Corner point of the box.\n        /// </summary>\n        public Point3d P4\n        {\n            get\n            {\n                return new Point3d(_center.X - 0.5 * _lx, _center.Y + 0.5 * _ly, _center.Z - 0.5 * _lz);\n            }\n        }\n\n        /// <summary>\n        /// Corner point of the box.\n        /// </summary>\n        public Point3d P5\n        {\n            get\n            {\n                return new Point3d(_center.X - 0.5 * _lx, _center.Y - 0.5 * _ly, _center.Z + 0.5 * _lz);\n            }\n        }\n\n        /// <summary>\n        /// Corner point of the box.\n        /// </summary>\n        public Point3d P6\n        {\n            get\n            {\n                return new Point3d(_center.X + 0.5 * _lx, _center.Y - 0.5 * _ly, _center.Z + 0.5 * _lz);\n            }\n        }\n\n        /// <summary>\n        /// Corner point of the box.\n        /// </summary>\n        public Point3d P7\n        {\n            get\n            {\n                return new Point3d(_center.X + 0.5 * _lx, _center.Y + 0.5 * _ly, _center.Z + 0.5 * _lz);\n            }\n        }\n\n        /// <summary>\n        /// Corner point of the box.\n        /// </summary>\n        public Point3d P8\n        {\n            get\n            {\n                return new Point3d(_center.X - 0.5 * _lx, _center.Y + 0.5 * _ly, _center.Z + 0.5 * _lz);\n            }\n        }\n\n        /// <summary>\n        /// List of corner points.\n        /// </summary>\n        public List<Point3d> ListOfPoints\n        {\n            get\n            {\n                lock (_lock)\n                {\n                    if (_list_p == null)\n                    {\n                        _list_p = new List<Point3d> { P1, P2, P3, P4, P5, P6, P7, P8 };\n                        return _list_p;\n                    }\n                    else\n                    {\n                        return _list_p;\n                    }\n                }\n            }\n        }\n\n        /// <summary>\n        /// List of triangles forming the box's surface\n        /// </summary>\n        public List<Triangle> ListOfTriangles\n        {\n            get\n            {\n                lock (_lock)\n                {\n                    if (_list_t == null)\n                    {\n                        Point3d P1 = this.P1;\n                        Point3d P2 = this.P2;\n                        Point3d P3 = this.P3;\n                        Point3d P4 = this.P4;\n                        Point3d P5 = this.P5;\n                        Point3d P6 = this.P6;\n                        Point3d P7 = this.P7;\n                        Point3d P8 = this.P8;\n                        _list_t = new List<Triangle> { };\n                        _list_t.Add(new Triangle(P1, P3, P2));\n                        _list_t.Add(new Triangle(P1, P4, P3));\n\n                        _list_t.Add(new Triangle(P1, P2, P6));\n                        _list_t.Add(new Triangle(P1, P6, P5));\n\n                        _list_t.Add(new Triangle(P2, P3, P7));\n                        _list_t.Add(new Triangle(P2, P7, P6));\n\n                        _list_t.Add(new Triangle(P3, P4, P8));\n                        _list_t.Add(new Triangle(P3, P8, P7));\n\n                        _list_t.Add(new Triangle(P4, P1, P5));\n                        _list_t.Add(new Triangle(P4, P5, P8));\n\n                        _list_t.Add(new Triangle(P5, P6, P7));\n                        _list_t.Add(new Triangle(P5, P7, P8));\n\n                        return _list_t;\n                    }\n                    else\n                    {\n                        return _list_t;\n                    }\n                }\n            }\n        }\n\n        /// <summary>\n        /// List of planes forming the box's surface\n        /// </summary>\n        public List<Plane3d> ListOfPlanes\n        {\n            get\n            {\n                lock (_lock)\n                {\n                    if (_list_plane == null)\n                    {\n                        _list_plane = new List<Plane3d> { };\n                        _list_plane.Add(new Plane3d(P1, -V1));\n                        _list_plane.Add(new Plane3d(P2, V1));\n                        _list_plane.Add(new Plane3d(P1, -V2));\n                        _list_plane.Add(new Plane3d(P4, V2));\n                        _list_plane.Add(new Plane3d(P1, -V3));\n                        _list_plane.Add(new Plane3d(P5, V3));\n\n                        return _list_plane;\n                    }\n                    else\n                    {\n                        return _list_plane;\n                    }\n                }\n            }\n        }\n\n        /// <summary>\n        /// List of edges forming the box\n        /// </summary>\n        public List<Segment3d> ListOfEdges\n        {\n            get\n            {\n                lock (_lock)\n                {\n                    if (_list_e == null)\n                    {\n                        _list_e = new List<Segment3d> { };\n                        _list_e.Add(new Segment3d(P1, P2));\n                        _list_e.Add(new Segment3d(P2, P3));\n                        _list_e.Add(new Segment3d(P3, P4));\n                        _list_e.Add(new Segment3d(P4, P1));\n                        _list_e.Add(new Segment3d(P5, P6));\n                        _list_e.Add(new Segment3d(P6, P7));\n                        _list_e.Add(new Segment3d(P7, P8));\n                        _list_e.Add(new Segment3d(P8, P5));\n                        _list_e.Add(new Segment3d(P1, P5));\n                        _list_e.Add(new Segment3d(P2, P6));\n                        _list_e.Add(new Segment3d(P3, P7));\n                        _list_e.Add(new Segment3d(P4, P8));\n\n                        return _list_e;\n                    }\n                    else\n                    {\n                        return _list_e;\n                    }\n                }\n            }\n        }\n\n        /// <summary>\n        /// Volume of the box.\n        /// </summary>\n        public double Volume\n        {\n            get { return _lx * _ly * _lz; }\n        }\n\n        /// <summary>\n        /// Surface area of the box.\n        /// </summary>\n        public double Area\n        {\n            get { return 2.0 * (_lx * _ly + _lx * _lz + _ly * _lz); }\n        }\n\n        /// <summary>\n        /// Length of the box diagonal.\n        /// </summary>\n        public double Diagonal\n        {\n            get { return Sqrt(_lx * _lx + _ly * _ly + _lz * _lz); }\n        }\n\n        /// <summary>\n        /// True if box is axis aligned\n        /// </summary>\n        public bool IsAxisAligned\n        {\n            get { return true; }\n        }\n\n        #endregion\n\n        #region \"BoundingBox\"\n        /// <summary>\n        /// Return minimum bounding box.\n        /// </summary>\n        public Box3d MinimumBoundingBox\n        {\n            get { return new Box3d(_center, _lx, _ly, _lz); }\n        }\n\n        /// <summary>\n        /// Return Axis Aligned Bounding Box (AABB) in given coordinate system.\n        /// </summary>\n        public Box3d BoundingBox(Coord3d coord = null)\n        {\n            coord = (coord == null) ? Coord3d.GlobalCS : coord;\n            Point3d c = _center.ConvertTo(coord);\n            double mx = c.X;\n            double my = c.Y;\n            double mz = c.Z;\n\n            foreach (Point3d p in this.ListOfPoints)\n            {\n                Point3d t = p.ConvertTo(coord);\n                if (t.X < mx) mx = t.X;\n                if (t.Y < my) my = t.Y;\n                if (t.Z < mz) mz = t.Z;\n            }\n\n            return new Box3d(c, 2.0 * (c.X - mx), 2.0 * (c.Y - my), 2.0 * (c.Z - mz), coord);\n        }\n\n        /// <summary>\n        /// Return bounding sphere.\n        /// </summary>\n        public Sphere BoundingSphere\n        {\n            get\n            {\n                double r = 0.5 * Sqrt(_lx * _lx + _ly * _ly + _lz * _lz);\n                return new Sphere(this.Center, r);\n            }\n        }\n        #endregion\n\n        /// <summary>\n        /// Return Axis Aligned Bounding Box (AABB) for a cloud of points.\n        /// </summary>\n        public static AABB BoundingBox(IEnumerable<Point3d> points)\n        {\n            double maxx = double.NegativeInfinity;\n            double maxy = double.NegativeInfinity;\n            double maxz = double.NegativeInfinity;\n            double minx = double.PositiveInfinity;\n            double miny = double.PositiveInfinity;\n            double minz = double.PositiveInfinity;\n\n            foreach (Point3d p in points)\n            {\n                Point3d t = p.ConvertToGlobal();\n                if (t.X > maxx) { maxx = t.X; }\n                if (t.Y > maxy) { maxy = t.Y; }\n                if (t.Z > maxz) { maxz = t.Z; }\n                if (t.X < minx) { minx = t.X; }\n                if (t.Y < miny) { miny = t.Y; }\n                if (t.Z < minz) { minz = t.Z; }\n            }\n\n            return new AABB(new Point3d(0.5 * (maxx + minx), 0.5 * (maxy + miny), 0.5 * (maxz + minz)), maxx - minx, maxy - miny, maxz - minz);\n        }\n\n        /// <summary>\n        /// Return union of two AABBs>\n        public static AABB Union(AABB box1, AABB box2)\n        {\n            double maxx = Max(box1.Xmax, box2.Xmax);\n            double maxy = Max(box1.Ymax, box2.Ymax);\n            double maxz = Max(box1.Zmax, box2.Zmax);\n            double minx = Min(box1.Xmin, box2.Xmin);\n            double miny = Min(box1.Ymin, box2.Ymin);\n            double minz = Min(box1.Zmin, box2.Zmin);\n\n            return new AABB(new Point3d(0.5 * (maxx + minx), 0.5 * (maxy + miny), 0.5 * (maxz + minz)), maxx - minx, maxy - miny, maxz - minz);\n        }\n\n\n        #region \"Intersection\"\n        /// <summary>\n        /// Get intersection of line with box.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'.\n        /// </summary>\n        public object IntersectionWith(Line3d l)\n        {\n            return _line_intersection(l, double.NegativeInfinity, double.PositiveInfinity);\n        }\n\n        /// <summary>\n        /// Get intersection of ray with box.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'.\n        /// </summary>\n        public object IntersectionWith(Ray3d r)\n        {\n            return _line_intersection(r.ToLine, 0.0, double.PositiveInfinity);\n        }\n\n        /// <summary>\n        /// Get intersection of segment with box.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'.\n        /// </summary>\n        public object IntersectionWith(Segment3d s)\n        {\n            return _line_intersection(s.Line, 0.0, s.Length);\n        }\n\n        /// <summary>\n        /// Check intersection of box with triangle\n        /// </summary>\n        public bool Intersects(Triangle t)\n        {\n            if (t.A.BelongsTo(this) || t.B.BelongsTo(this) || t.C.BelongsTo(this))\n            {\n                return true;\n            }\n\n            foreach (Triangle bt in this.ListOfTriangles)\n            {\n                if (bt.Intersects(t)) return true;\n            }\n\n            return false;\n        }\n\n        /// <summary>\n        /// Check intersection of two boxes (only for AABB boxes, no check is performed for speed)\n        /// </summary>\n        public bool Intersects(Box3d box)\n        {\n            bool x = Abs(this._center.X - box._center.X) <= 0.5 * (this.L1 + box.L1) ? true : false;\n            bool y = Abs(this._center.Y - box._center.Y) <= 0.5 * (this.L2 + box.L2) ? true : false;\n            bool z = Abs(this._center.Z - box._center.Z) <= 0.5 * (this.L3 + box.L3) ? true : false;\n\n            return x && y && z;\n        }\n\n        /// <summary>\n        /// Check intersection of two AABB\n        /// </summary>\n        public bool Intersects(AABB box)\n        {\n            bool x = Abs(this._center.X - box._center.X) <= 0.5 * (this.L1 + box.L1) ? true : false;\n            bool y = Abs(this._center.Y - box._center.Y) <= 0.5 * (this.L2 + box.L2) ? true : false;\n            bool z = Abs(this._center.Z - box._center.Z) <= 0.5 * (this.L3 + box.L3) ? true : false;\n\n            return x && y && z;\n        }\n\n        /// <summary>\n        /// Intersection check between circle and box\n        /// </summary>\n        public bool Intersects(Circle3d c)\n        {\n            //if (c.Center.IsInside(this)) return true;\n            double dist = c._point.DistanceTo(this);\n            if (dist > c.R) return false;\n            if (dist < GeometRi3D.Tolerance) return true;\n\n            foreach (Triangle triangle in ListOfTriangles)\n            {\n                if (c.Intersects(triangle)) return true;\n            }\n            return false;\n        }\n\n        /// <summary>\n        /// Check if AABB is located inside box.\n        /// </summary>\n        public bool IsInside(Box3d box)\n        {\n            foreach (Point3d p in ListOfPoints)\n            {\n                if (!p.IsInside(box)) return false;\n            }\n            return true;\n        }\n\n        /// <summary>\n        /// Check if AABB is located inside box.\n        /// </summary>\n        public bool IsInside(AABB box)\n        {\n            foreach (Point3d p in ListOfPoints)\n            {\n                if (!p.IsInside(box)) return false;\n            }\n            return true;\n        }\n\n        /// <summary>\n        /// Intersection of two AABB (null for non-intersecting AABB)\n        /// </summary>\n        public AABB IntersectionWith(AABB box)\n        {\n            double x1min = this._center.X - 0.5 * this.L1;\n            double x1max = this._center.X + 0.5 * this.L1;\n            double y1min = this._center.Y - 0.5 * this.L2;\n            double y1max = this._center.Y + 0.5 * this.L2;\n            double z1min = this._center.Z - 0.5 * this.L3;\n            double z1max = this._center.Z + 0.5 * this.L3;\n\n            double x2min = box._center.X - 0.5 * box.L1;\n            double x2max = box._center.X + 0.5 * box.L1;\n            double y2min = box._center.Y - 0.5 * box.L2;\n            double y2max = box._center.Y + 0.5 * box.L2;\n            double z2min = box._center.Z - 0.5 * box.L3;\n            double z2max = box._center.Z + 0.5 * box.L3;\n\n            double xmin, xmax, ymin, ymax, zmin, zmax;\n\n            xmin = Max(x1min, x2min);\n            xmax = Min(x1max, x2max);\n            if (xmax >= xmin)\n            {\n                ymin = Max(y1min, y2min);\n                ymax = Min(y1max, y2max);\n                if (ymax >= ymin)\n                {\n                    zmin = Max(z1min, z2min);\n                    zmax = Min(z1max, z2max);\n                    if (zmax >= zmin)\n                    {\n                        return new AABB(new Point3d(xmin, ymin, zmin), new Point3d(xmax, ymax, zmax));\n                    }\n                    else\n                    {\n                        return null;\n                    }\n                }\n                else\n                {\n                    return null;\n                }\n            }\n            else\n            {\n                return null;\n            }\n\n        }\n\n        private object _line_intersection(Line3d l, double t0, double t1)\n        {\n            // Smith's algorithm:\n            // \"An Efficient and Robust Ray–Box Intersection Algorithm\"\n            // Amy Williams, Steve Barrus, R. Keith Morley, Peter Shirley\n            // http://www.cs.utah.edu/~awilliam/box/box.pdf\n\n            // Modified to allow tolerance based checks\n\n            // Relative tolerance ================================\n            if (!GeometRi3D.UseAbsoluteTolerance)\n            {\n                double tol = GeometRi3D.Tolerance;\n                GeometRi3D.Tolerance = tol * this.Diagonal;\n                GeometRi3D.UseAbsoluteTolerance = true;\n                object result = _line_intersection(l, t0, t1);\n                GeometRi3D.UseAbsoluteTolerance = false;\n                GeometRi3D.Tolerance = tol;\n                return result;\n            }\n            //====================================================\n\n            // Define local CS aligned with box\n            Coord3d local_CS = this.LocalCoord();\n\n            Point3d Pmin = this.P1.ConvertTo(local_CS);\n            Point3d Pmax = this.P7.ConvertTo(local_CS);\n\n            l = new Line3d(l.Point.ConvertTo(local_CS), l.Direction.ConvertTo(local_CS).Normalized);\n\n            double tmin, tmax, tymin, tymax, tzmin, tzmax;\n            double divx = 1 / l.Direction.X;\n            if (divx >= 0)\n            {\n                tmin = (Pmin.X - l.Point.X) * divx;\n                tmax = (Pmax.X - l.Point.X) * divx;\n            }\n            else\n            {\n                tmin = (Pmax.X - l.Point.X) * divx;\n                tmax = (Pmin.X - l.Point.X) * divx;\n            }\n\n            double divy = 1 / l.Direction.Y;\n            if (divy >= 0)\n            {\n                tymin = (Pmin.Y - l.Point.Y) * divy;\n                tymax = (Pmax.Y - l.Point.Y) * divy;\n            }\n            else\n            {\n                tymin = (Pmax.Y - l.Point.Y) * divy;\n                tymax = (Pmin.Y - l.Point.Y) * divy;\n            }\n\n            if (GeometRi3D.Greater(tmin, tymax) || GeometRi3D.Greater(tymin, tmax))\n                return null;\n            if (GeometRi3D.Greater(tymin, tmin))\n                tmin = tymin;\n            if (GeometRi3D.Smaller(tymax, tmax))\n                tmax = tymax;\n\n            double divz = 1 / l.Direction.Z;\n            if (divz >= 0)\n            {\n                tzmin = (Pmin.Z - l.Point.Z) * divz;\n                tzmax = (Pmax.Z - l.Point.Z) * divz;\n            }\n            else\n            {\n                tzmin = (Pmax.Z - l.Point.Z) * divz;\n                tzmax = (Pmin.Z - l.Point.Z) * divz;\n            }\n\n            if (GeometRi3D.Greater(tmin, tzmax) || GeometRi3D.Greater(tzmin, tmax))\n                return null;\n            if (GeometRi3D.Greater(tzmin, tmin))\n                tmin = tzmin;\n            if (GeometRi3D.Smaller(tzmax, tmax))\n                tmax = tzmax;\n\n            // Now check the overlapping portion of the segments\n            // This part is missing in the original algorithm\n            if (GeometRi3D.Greater(tmin, t1))\n                return null;\n            if (GeometRi3D.Smaller(tmax, t0))\n                return null;\n\n            if (GeometRi3D.Smaller(tmin, t0))\n                tmin = t0;\n            if (GeometRi3D.Greater(tmax, t1))\n                tmax = t1;\n\n            if (GeometRi3D.AlmostEqual(tmin, tmax))\n            {\n                return l.Point.Translate(tmin * l.Direction);\n            }\n            else\n            {\n                return new Segment3d(l.Point.Translate(tmin * l.Direction), l.Point.Translate(tmax * l.Direction));\n            }\n        }\n        #endregion\n\n\n        /// <summary>\n        /// Local coordinate system with origin in box's center and aligned with box\n        /// </summary>\n        public Coord3d LocalCoord()\n        {\n            return new Coord3d(this._center, V1, V2);\n        }\n\n        /// <summary>\n        /// Point on box (including interior points) closest to target point \"p\".\n        /// </summary>\n        public Point3d ClosestPoint(Point3d p)\n        {\n            p = p.ConvertToGlobal();\n            double x = GeometRi3D.Clamp(p.X, this._center.X - _lx / 2, this._center.X + _lx / 2);\n            double y = GeometRi3D.Clamp(p.Y, this._center.Y - _ly / 2, this._center.Y + _ly / 2);\n            double z = GeometRi3D.Clamp(p.Z, this._center.Z - _lz / 2, this._center.Z + _lz / 2);\n\n            return new Point3d(x, y, z);\n        }\n\n        /// <summary>\n        /// Distance from box to point (zero will be returned for point located inside box)\n        /// </summary>\n        public double DistanceTo(Point3d p)\n        {\n            return ClosestPoint(p).DistanceTo(p);\n        }\n\n        /// <summary>\n        /// Distance between two AABB\n        /// </summary>\n        public double DistanceTo(AABB box)\n        {\n            double dx = Abs(_center.X - box._center.X) - 0.5 * (_lx + box._lx);\n            double dy = Abs(_center.Y - box._center.Y) - 0.5 * (_ly + box._ly);\n            double dz = Abs(_center.Z - box._center.Z) - 0.5 * (_lz + box._lz);\n            if (dx < 0) { dx = 0; }\n            if (dy < 0) { dy = 0; }\n            if (dz < 0) { dz = 0; }\n            return Sqrt(dx * dx + dy * dy + dz * dz);\n        }\n\n        /// <summary>\n        /// Shortest distance from box to sphere\n        /// </summary>\n        public double DistanceTo(Sphere s)\n        {\n            Point3d p = this.ClosestPoint(s._point);\n            double dist = p.DistanceTo(s._point);\n            return dist <= s.R ? 0.0 : dist - s.R;\n        }\n\n        /// <summary>\n        /// Shortest distance from box to circle\n        /// </summary>\n        public double DistanceTo(Circle3d c)\n        {\n            if (c._point.IsInside(this))\n            {\n                return 0;\n            }\n            double min_dist = Double.PositiveInfinity;\n            foreach (Triangle triangle in ListOfTriangles)\n            {\n                double dist = c.DistanceTo(triangle);\n                if (dist <= GeometRi3D.Tolerance) return 0;\n                if (dist < min_dist) min_dist = dist;\n            }\n            return min_dist;\n        }\n\n\n\n        internal override int _PointLocation(Point3d p)\n        {\n            Coord3d coord = this.LocalCoord();\n            p = p.ConvertTo(coord);\n            if (GeometRi3D.UseAbsoluteTolerance)\n            {\n                if ((Abs(p.X) - L1 / 2) <= GeometRi3D.Tolerance && (Abs(p.Y) - L2 / 2) <= GeometRi3D.Tolerance && (Abs(p.Z) - L3 / 2) <= GeometRi3D.Tolerance)\n                {\n                    if ((Abs(p.X) - L1 / 2) < -GeometRi3D.Tolerance && (Abs(p.Y) - L2 / 2) < -GeometRi3D.Tolerance && (Abs(p.Z) - L3 / 2) < -GeometRi3D.Tolerance)\n                    {\n                        return 1; // Point is strictly inside box\n                    }\n                    else\n                    {\n                        return 0; // Point is on boundary\n                    }\n                }\n                else\n                {\n                    return -1; // Point is outside\n                }\n            }\n            else\n            {\n                double tol = GeometRi3D.Tolerance;\n                GeometRi3D.Tolerance = tol * this.Diagonal;\n                GeometRi3D.UseAbsoluteTolerance = true;\n                int result = this._PointLocation(p);\n                GeometRi3D.UseAbsoluteTolerance = false;\n                GeometRi3D.Tolerance = tol;\n                return result;\n            }\n        }\n\n        #region \"TranslateRotateReflect\"\n        /// <summary>\n        /// Translate box by a vector\n        /// </summary>\n        public AABB Translate(Vector3d v)\n        {\n            return new AABB(_center.Translate(v), _lx, _ly, _lz);\n        }\n\n\n        /// <summary>\n        /// Reflect box in given point\n        /// <para>The order of corner points will be changed during reflection operation.</para>\n        /// </summary>\n        public virtual AABB ReflectIn(Point3d p)\n        {\n            Point3d new_center = this.Center.ReflectIn(p);\n            return new AABB(new_center, _lx, _ly, _lz);\n        }\n\n        /// <summary>\n        /// Scale box relative to given point\n        /// </summary>\n        public virtual AABB Scale(double scale, Point3d scaling_center)\n        {\n            Point3d new_center = scaling_center + scale * (this._center - scaling_center);\n            return new AABB(new_center, scale * _lx, scale * _ly, scale * _lz);\n        }\n\n        #endregion\n\n\n        /// <summary>\n        /// Determines whether two objects are equal.\n        /// </summary>\n        public override bool Equals(object obj)\n        {\n            if (obj == null || (!object.ReferenceEquals(this.GetType(), obj.GetType())))\n            {\n                return false;\n            }\n            AABB b = (AABB)obj;\n\n            if (GeometRi3D.UseAbsoluteTolerance)\n            {\n                return this._center == b._center &&\n                       GeometRi3D.AlmostEqual(L1, b.L1) &&\n                       GeometRi3D.AlmostEqual(L2, b.L2) &&\n                       GeometRi3D.AlmostEqual(L3, b.L3);\n            }\n            else\n            {\n                double tol = GeometRi3D.Tolerance;\n                GeometRi3D.Tolerance = tol * this.Diagonal;\n                GeometRi3D.UseAbsoluteTolerance = true;\n                bool result = this.Equals(b);\n                GeometRi3D.UseAbsoluteTolerance = false;\n                GeometRi3D.Tolerance = tol;\n                return result;\n            }\n\n        }\n\n        /// <summary>\n        /// Returns the hashcode for the object.\n        /// </summary>\n        public override int GetHashCode()\n        {\n            int hash_code = GeometRi3D.HashFunction(_lx.GetHashCode(), _ly.GetHashCode(), _lz.GetHashCode());\n            return GeometRi3D.HashFunction(_center.GetHashCode(), hash_code);\n        }\n\n        /// <summary>\n        /// String representation of an object in global coordinate system.\n        /// </summary>\n        public override string ToString()\n        {\n            return ToString(Coord3d.GlobalCS);\n        }\n\n        /// <summary>\n        /// String representation of an object in reference coordinate system.\n        /// </summary>\n        public string ToString(Coord3d coord)\n        {\n            string nl = System.Environment.NewLine;\n\n            if (coord == null) { coord = Coord3d.GlobalCS; }\n            Point3d p = _center.ConvertTo(coord);\n\n            string str = string.Format(\"Box3d (reference coord.sys. \") + coord.Name + \"):\" + nl;\n            str += string.Format(\"Center -> ({0,10:g5}, {1,10:g5}, {2,10:g5})\", p.X, p.Y, p.Z) + nl;\n            str += string.Format(\"Lx, Ly, Lz -> ({0,10:g5}, {1,10:g5}, {2,10:g5})\", _lx, _ly, _lz) + nl;\n            return str;\n        }\n\n        // Operators overloads\n        //-----------------------------------------------------------------\n        public static bool operator ==(AABB b1, AABB b2)\n        {\n            if (object.ReferenceEquals(b1, null))\n                return object.ReferenceEquals(b2, null);\n            return b1.Equals(b2);\n        }\n        public static bool operator !=(AABB b1, AABB b2)\n        {\n            if (object.ReferenceEquals(b1, null))\n                return !object.ReferenceEquals(b2, null);\n            return !b1.Equals(b2);\n        }\n    }\n}\n\n"
  },
  {
    "path": "GeometRi/AbstractClass.cs",
    "content": "﻿using System;\nusing static System.Math;\nusing System.Collections.Generic;\n\nnamespace GeometRi\n{\n\n#if NET20_OR_GREATER\n    [Serializable]\n#endif\n    abstract public class FiniteObject\n    {\n        abstract internal int _PointLocation(Point3d p);\n    }\n#if NET20_OR_GREATER\n    [Serializable]\n#endif\n    abstract public class PlanarFiniteObject : FiniteObject\n    {\n        abstract internal Plane3d Plane { get; }\n    }\n#if NET20_OR_GREATER\n    [Serializable]\n#endif\n    abstract public class LinearFiniteObject : FiniteObject\n    {\n        abstract internal Line3d Line { get; }\n        abstract internal Vector3d Vector { get; }\n        abstract internal Ray3d Ray { get; }\n    }\n}\n"
  },
  {
    "path": "GeometRi/Box3d.cs",
    "content": "﻿using System;\nusing static System.Math;\nusing System.Collections.Generic;\n\nnamespace GeometRi\n{\n    /// <summary>\n    /// Arbitrary oriented 3D box, can be degenerated with one or more dimensions equal 0.\n    /// </summary>\n#if NET20_OR_GREATER\n    [Serializable]\n#endif\n    public class Box3d : FiniteObject, IFiniteObject\n    {\n\n        internal Point3d _center;\n        internal double _lx, _ly, _lz;\n        internal Vector3d _v1, _v2, _v3;\n        private Rotation _r;\n        private Coord3d _local_coord = null;\n\n        private List<Point3d> _list_p = null;\n        private List<Triangle> _list_t = null;\n        private List<Segment3d> _list_e = null;\n        private List<Plane3d> _list_plane = null;\n        private static object _lock = new object();\n\n        #region \"Constructors\"\n\n        /// <summary>\n        /// Default constructor, initializes box in the origin of the global coordinate system aligned with coordinate axes.\n        /// </summary>\n        public Box3d(Point3d center, double lx, double ly, double lz)\n        {\n            _center = center.Copy();\n            _lx = lx;\n            _ly = ly;\n            _lz = lz;\n            _v1 = new Vector3d(1, 0, 0);\n            _v2 = new Vector3d(0, 1, 0);\n            _v3 = new Vector3d(0, 0, 1);\n            _r = new Rotation();\n            _local_coord = new Coord3d(_center, _r.ConvertToGlobal().ToRotationMatrix.Transpose());\n        }\n\n        /// <summary>\n        /// Initializes unit box in the origin of the reference coordinate system aligned with coordinate axes.\n        /// </summary>\n        /// <param name=\"coord\">Reference coordinate system.</param>\n        public Box3d(Coord3d coord = null)\n        {\n            _center = new Point3d(coord);\n            _lx = _ly = _lz = 1.0;\n            _v1 = new Vector3d(1, 0, 0, coord);\n            _v2 = new Vector3d(0, 1, 0, coord);\n            _v3 = new Vector3d(0, 0, 1, coord);\n            _r = new Rotation(coord);\n            if (coord != null)\n            {\n                // do not set local_coord for box aligned with global CS\n                _local_coord = new Coord3d(_center, _r.ConvertToGlobal().ToRotationMatrix.Transpose());\n            }\n        }\n\n        /// <summary>\n        /// Initializes box with specified dimensions and orientation defined by rotation object.\n        /// </summary>\n        /// <param name=\"center\">Center point of the box.</param>\n        /// <param name=\"lx\">First dimension.</param>\n        /// <param name=\"ly\">Second dimension.</param>\n        /// <param name=\"lz\">Third dimension.</param>\n        /// <param name=\"r\">Orientation of the box, defined as rotation from axis aligned position (in global CS) to final position.</param>\n        public Box3d(Point3d center, double lx, double ly, double lz, Rotation r)\n        {\n            _center = center.Copy();\n            _lx = lx;\n            _ly = ly;\n            _lz = lz;\n            _r = r.Copy();\n            _v1 = _r.ConvertToGlobal().ToRotationMatrix.Column1;\n            _v2 = _r.ConvertToGlobal().ToRotationMatrix.Column2;\n            _v3 = _r.ConvertToGlobal().ToRotationMatrix.Column3;\n            _local_coord = new Coord3d(_center, _r.ConvertToGlobal().ToRotationMatrix.Transpose());\n        }\n\n        /// <summary>\n        /// Initializes axis aligned box in local coordinate system.\n        /// </summary>\n        /// <param name=\"center\">Center point of the box.</param>\n        /// <param name=\"lx\">First dimension.</param>\n        /// <param name=\"ly\">Second dimension.</param>\n        /// <param name=\"lz\">Third dimension.</param>\n        /// <param name=\"coord\">Local coordinate system.</param>\n        public Box3d(Point3d center, double lx, double ly, double lz, Coord3d coord)\n        {\n            _center = center.Copy();\n            _lx = lx;\n            _ly = ly;\n            _lz = lz;\n            _v1 = new Vector3d(1, 0, 0, coord);\n            _v2 = new Vector3d(0, 1, 0, coord);\n            _v3 = new Vector3d(0, 0, 1, coord);\n            _r = new Rotation(coord);\n            _local_coord = new Coord3d(_center, _r.ConvertToGlobal().ToRotationMatrix.Transpose());\n        }\n\n        /// <summary>\n        /// Initializes axis aligned box by two points.\n        /// </summary>\n        /// <param name=\"p_min\">Minimum corner of the box</param>\n        /// <param name=\"p_max\">Maximum corner of the box</param>\n        public Box3d(Point3d p_min, Point3d p_max)\n        {\n            _center = (p_min + p_max) / 2;\n            Vector3d v = new Vector3d(p_min, p_max).ConvertToGlobal();\n            _lx = v.X;\n            _ly = v.Y;\n            _lz = v.Z;\n            _v1 = new Vector3d(1, 0, 0);\n            _v2 = new Vector3d(0, 1, 0);\n            _v3 = new Vector3d(0, 0, 1);\n            _r = new Rotation();\n            _local_coord = new Coord3d(_center, _r.ConvertToGlobal().ToRotationMatrix.Transpose());\n        }\n        #endregion\n\n        /// <summary>\n        /// Creates copy of the object\n        /// </summary>\n        public Box3d Copy()\n        {\n            return new Box3d(_center, _lx, _ly, _lz, _r);\n        }\n\n#region \"Properties\"\n        /// <summary>\n        /// Center point of the box.\n        /// </summary>\n        public Point3d Center\n        {\n            get { return _center.Copy(); }\n            set {\n                _center = value.Copy();\n                _list_p = null;\n                _list_t = null;\n                _list_e = null;\n                _list_plane = null;\n                _local_coord = new Coord3d(_center, _r.ConvertToGlobal().ToRotationMatrix.Transpose());\n            }\n        }\n\n        /// <summary>\n        /// First dimension.\n        /// </summary>\n        public double L1\n        {\n            get { return _lx; }\n            set {\n                _lx = value;\n                _list_p = null;\n                _list_t = null;\n                _list_e = null;\n                _list_plane = null;\n            }\n        }\n\n        /// <summary>\n        /// Second dimension.\n        /// </summary>\n        public double L2\n        {\n            get { return _ly; }\n            set {\n                _ly = value;\n                _list_p = null;\n                _list_t = null;\n                _list_e = null;\n                _list_plane = null;\n            }\n        }\n\n        /// <summary>\n        /// Third dimension.\n        /// </summary>\n        public double L3\n        {\n            get { return _lz; }\n            set {\n                _lz = value;\n                _list_p = null;\n                _list_t = null;\n                _list_e = null;\n                _list_plane = null;\n            }\n        }\n\n        /// <summary>\n        /// Orientation of the first dimension of the box.\n        /// </summary>\n        public Vector3d V1\n        {\n            get { return _v1; }\n        }\n\n        /// <summary>\n        /// Orientation of the second dimension of the box.\n        /// </summary>\n        public Vector3d V2\n        {\n            get { return _v2; }\n        }\n\n        /// <summary>\n        /// Orientation of the third dimension of the box.\n        /// </summary>\n        public Vector3d V3\n        {\n            get { return _v3; }\n        }\n\n        /// <summary>\n        /// Orientation of the box, defined as rotation from axis aligned position (in global CS) to final position.\n        /// </summary>\n        public Rotation Orientation\n        {\n            get { return _r.Copy(); }\n            set {\n                _r = value.Copy();\n                _v1 = _r.ConvertToGlobal().ToRotationMatrix.Column1;\n                _v2 = _r.ConvertToGlobal().ToRotationMatrix.Column2;\n                _v3 = _r.ConvertToGlobal().ToRotationMatrix.Column3;\n                _list_p = null;\n                _list_t = null;\n                _list_e = null;\n                _list_plane = null;\n                _local_coord = new Coord3d(_center, _r.ConvertToGlobal().ToRotationMatrix.Transpose());\n            }\n        }\n\n        /// <summary>\n        /// Corner point of the box.\n        /// </summary>\n        public Point3d P1\n        {\n            get\n            {\n                return _center.ConvertToGlobal() + 0.5 * (\n                    -_lx * _r.ConvertToGlobal().ToRotationMatrix.Column1.ToPoint\n                    - _ly * _r.ConvertToGlobal().ToRotationMatrix.Column2.ToPoint\n                    - _lz * _r.ConvertToGlobal().ToRotationMatrix.Column3.ToPoint);\n            }\n        }\n\n        /// <summary>\n        /// Corner point of the box.\n        /// </summary>\n        public Point3d P2\n        {\n            get\n            {\n                return _center.ConvertToGlobal() + 0.5 * (\n                    +_lx * _r.ConvertToGlobal().ToRotationMatrix.Column1.ToPoint\n                    - _ly * _r.ConvertToGlobal().ToRotationMatrix.Column2.ToPoint\n                    - _lz * _r.ConvertToGlobal().ToRotationMatrix.Column3.ToPoint);\n            }\n        }\n\n        /// <summary>\n        /// Corner point of the box.\n        /// </summary>\n        public Point3d P3\n        {\n            get\n            {\n                return _center.ConvertToGlobal() + 0.5 * (\n                    +_lx * _r.ConvertToGlobal().ToRotationMatrix.Column1.ToPoint\n                    + _ly * _r.ConvertToGlobal().ToRotationMatrix.Column2.ToPoint\n                    - _lz * _r.ConvertToGlobal().ToRotationMatrix.Column3.ToPoint);\n            }\n        }\n\n        /// <summary>\n        /// Corner point of the box.\n        /// </summary>\n        public Point3d P4\n        {\n            get\n            {\n                return _center.ConvertToGlobal() + 0.5 * (\n                    -_lx * _r.ConvertToGlobal().ToRotationMatrix.Column1.ToPoint\n                    + _ly * _r.ConvertToGlobal().ToRotationMatrix.Column2.ToPoint\n                    - _lz * _r.ConvertToGlobal().ToRotationMatrix.Column3.ToPoint);\n            }\n        }\n\n        /// <summary>\n        /// Corner point of the box.\n        /// </summary>\n        public Point3d P5\n        {\n            get\n            {\n                return _center.ConvertToGlobal() + 0.5 * (\n                    -_lx * _r.ConvertToGlobal().ToRotationMatrix.Column1.ToPoint\n                    - _ly * _r.ConvertToGlobal().ToRotationMatrix.Column2.ToPoint\n                    + _lz * _r.ConvertToGlobal().ToRotationMatrix.Column3.ToPoint);\n            }\n        }\n\n        /// <summary>\n        /// Corner point of the box.\n        /// </summary>\n        public Point3d P6\n        {\n            get\n            {\n                return _center.ConvertToGlobal() + 0.5 * (\n                    +_lx * _r.ConvertToGlobal().ToRotationMatrix.Column1.ToPoint\n                    - _ly * _r.ConvertToGlobal().ToRotationMatrix.Column2.ToPoint\n                    + _lz * _r.ConvertToGlobal().ToRotationMatrix.Column3.ToPoint);\n            }\n        }\n\n        /// <summary>\n        /// Corner point of the box.\n        /// </summary>\n        public Point3d P7\n        {\n            get\n            {\n                return _center.ConvertToGlobal() + 0.5 * (\n                    +_lx * _r.ConvertToGlobal().ToRotationMatrix.Column1.ToPoint\n                    + _ly * _r.ConvertToGlobal().ToRotationMatrix.Column2.ToPoint\n                    + _lz * _r.ConvertToGlobal().ToRotationMatrix.Column3.ToPoint);\n            }\n        }\n\n        /// <summary>\n        /// Corner point of the box.\n        /// </summary>\n        public Point3d P8\n        {\n            get\n            {\n                return _center.ConvertToGlobal() + 0.5 * (\n                    -_lx * _r.ConvertToGlobal().ToRotationMatrix.Column1.ToPoint\n                    + _ly * _r.ConvertToGlobal().ToRotationMatrix.Column2.ToPoint\n                    + _lz * _r.ConvertToGlobal().ToRotationMatrix.Column3.ToPoint);\n            }\n        }\n\n        /// <summary>\n        /// List of corner points.\n        /// </summary>\n        public List<Point3d> ListOfPoints\n        {\n            get\n            {\n                lock (_lock)\n                {\n                    if (_list_p == null)\n                    {\n                        _list_p = new List<Point3d> { P1, P2, P3, P4, P5, P6, P7, P8 };\n                        return _list_p;\n                    }\n                    else\n                    {\n                        return _list_p;\n                    }\n                }\n            }\n        }\n\n        /// <summary>\n        /// List of triangles forming the box's surface\n        /// </summary>\n        public List<Triangle> ListOfTriangles\n        {\n            get\n            {\n                lock (_lock)\n                {\n                    if (_list_t == null)\n                    {\n                        Point3d P1 = this.P1;\n                        Point3d P2 = this.P2;\n                        Point3d P3 = this.P3;\n                        Point3d P4 = this.P4;\n                        Point3d P5 = this.P5;\n                        Point3d P6 = this.P6;\n                        Point3d P7 = this.P7;\n                        Point3d P8 = this.P8;\n                        _list_t = new List<Triangle> { };\n                        _list_t.Add(new Triangle(P1, P3, P2));\n                        _list_t.Add(new Triangle(P1, P4, P3));\n\n                        _list_t.Add(new Triangle(P1, P2, P6));\n                        _list_t.Add(new Triangle(P1, P6, P5));\n\n                        _list_t.Add(new Triangle(P2, P3, P7));\n                        _list_t.Add(new Triangle(P2, P7, P6));\n\n                        _list_t.Add(new Triangle(P3, P4, P8));\n                        _list_t.Add(new Triangle(P3, P8, P7));\n\n                        _list_t.Add(new Triangle(P4, P1, P5));\n                        _list_t.Add(new Triangle(P4, P5, P8));\n\n                        _list_t.Add(new Triangle(P5, P6, P7));\n                        _list_t.Add(new Triangle(P5, P7, P8));\n\n                        return _list_t;\n                    }\n                    else\n                    {\n                        return _list_t;\n                    }\n                }\n            }\n        }\n\n        /// <summary>\n        /// List of planes forming the box's surface\n        /// </summary>\n        public List<Plane3d> ListOfPlanes\n        {\n            get\n            {\n                lock (_lock)\n                {\n                    if (_list_plane == null)\n                    {\n                        _list_plane = new List<Plane3d> { };\n                        _list_plane.Add(new Plane3d(P1, -V1));\n                        _list_plane.Add(new Plane3d(P2, V1));\n                        _list_plane.Add(new Plane3d(P1, -V2));\n                        _list_plane.Add(new Plane3d(P4, V2));\n                        _list_plane.Add(new Plane3d(P1, -V3));\n                        _list_plane.Add(new Plane3d(P5, V3));\n\n                        return _list_plane;\n                    }\n                    else\n                    {\n                        return _list_plane;\n                    }\n                }\n            }\n        }\n\n        /// <summary>\n        /// List of edges forming the box\n        /// </summary>\n        public List<Segment3d> ListOfEdges\n        {\n            get\n            {\n                lock (_lock)\n                {\n                    if (_list_e == null)\n                    {\n                        _list_e = new List<Segment3d> { };\n                        _list_e.Add(new Segment3d(P1, P2));\n                        _list_e.Add(new Segment3d(P2, P3));\n                        _list_e.Add(new Segment3d(P3, P4));\n                        _list_e.Add(new Segment3d(P4, P1));\n                        _list_e.Add(new Segment3d(P5, P6));\n                        _list_e.Add(new Segment3d(P6, P7));\n                        _list_e.Add(new Segment3d(P7, P8));\n                        _list_e.Add(new Segment3d(P8, P5));\n                        _list_e.Add(new Segment3d(P1, P5));\n                        _list_e.Add(new Segment3d(P2, P6));\n                        _list_e.Add(new Segment3d(P3, P7));\n                        _list_e.Add(new Segment3d(P4, P8));\n\n                        return _list_e;\n                    }\n                    else\n                    {\n                        return _list_e;\n                    }\n                }\n            }\n        }\n\n        /// <summary>\n        /// Volume of the box.\n        /// </summary>\n        public double Volume\n        {\n            get { return _lx * _ly * _lz; }\n        }\n\n        /// <summary>\n        /// Surface area of the box.\n        /// </summary>\n        public double Area\n        {\n            get { return 2.0 * (_lx*_ly + _lx*_lz + _ly*_lz); }\n        }\n\n        /// <summary>\n        /// Length of the box diagonal.\n        /// </summary>\n        public double Diagonal\n        {\n            get { return Sqrt(_lx * _lx + _ly * _ly + _lz * _lz); }\n        }\n\n        /// <summary>\n        /// True if box is axis aligned\n        /// </summary>\n        public bool IsAxisAligned\n        {\n            get { return _r.ToRotationMatrix.IsIdentity; }\n        }\n\n#endregion\n\n#region \"BoundingBox\"\n        /// <summary>\n        /// Return minimum bounding box.\n        /// </summary>\n        public Box3d MinimumBoundingBox\n        {\n            get { return this.Copy(); }\n        }\n\n        /// <summary>\n        /// Return Axis Aligned Bounding Box (AABB).\n        /// </summary>\n        public AABB AABB\n        {\n            get { return GeometRi.AABB.BoundingBox(this.ListOfPoints); }\n        }\n\n        /// <summary>\n        /// Return Bounding Box in given coordinate system.\n        /// </summary>\n        public Box3d BoundingBox(Coord3d coord = null)\n        {\n            coord = (coord == null) ? Coord3d.GlobalCS : coord;\n            Point3d c = _center.ConvertTo(coord);\n            double mx = c.X;\n            double my = c.Y;\n            double mz = c.Z;\n\n            foreach (Point3d p in this.ListOfPoints)\n            {\n                Point3d t = p.ConvertTo(coord);\n                if (t.X < mx) mx = t.X;\n                if (t.Y < my) my = t.Y;\n                if (t.Z < mz) mz = t.Z;\n            }\n\n            return new Box3d(c, 2.0 * (c.X - mx), 2.0 * (c.Y - my), 2.0 * (c.Z - mz), coord);\n        }\n\n        /// <summary>\n        /// Return bounding sphere.\n        /// </summary>\n        public Sphere BoundingSphere\n        {\n            get\n            {\n                double r = 0.5 * Sqrt(_lx * _lx + _ly * _ly + _lz * _lz);\n                return new Sphere(this.Center, r);\n            }\n        }\n        #endregion\n\n        /// <summary>\n        /// Return Bounding Box for a cloud of points.\n        /// </summary>\n        public static Box3d BoundingBox(IEnumerable<Point3d> points, Coord3d coord = null)\n        {\n            coord = (coord == null) ? Coord3d.GlobalCS : coord;\n\n            double maxx = double.NegativeInfinity;\n            double maxy = double.NegativeInfinity;\n            double maxz = double.NegativeInfinity;\n            double minx = double.PositiveInfinity;\n            double miny = double.PositiveInfinity;\n            double minz = double.PositiveInfinity;\n\n            foreach (Point3d p in points)\n            {\n                Point3d t = p.ConvertTo(coord);\n                if (t.X > maxx) { maxx = t.X; }\n                if (t.Y > maxy) { maxy = t.Y; }\n                if (t.Z > maxz) { maxz = t.Z; }\n                if (t.X < minx) { minx = t.X; }\n                if (t.Y < miny) { miny = t.Y; }\n                if (t.Z < minz) { minz = t.Z; }\n            }\n\n            return new Box3d(new Point3d(0.5*(maxx + minx), 0.5 * (maxy + miny), 0.5 * (maxz + minz)), maxx - minx, maxy - miny, maxz - minz, coord);\n        }\n\n\n        #region \"Intersection\"\n        /// <summary>\n        /// Get intersection of line with box.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'.\n        /// </summary>\n        public object IntersectionWith(Line3d l)\n        {\n            return _line_intersection(l, double.NegativeInfinity, double.PositiveInfinity);\n        }\n\n        /// <summary>\n        /// Get intersection of ray with box.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'.\n        /// </summary>\n        public object IntersectionWith(Ray3d r)\n        {\n            return _line_intersection(r.ToLine, 0.0, double.PositiveInfinity);\n        }\n\n        /// <summary>\n        /// Get intersection of segment with box.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'.\n        /// </summary>\n        public object IntersectionWith(Segment3d s)\n        {\n            return _line_intersection(s.Line, 0.0, s.Length);\n        }\n\n        /// <summary>\n        /// Check intersection of box with triangle\n        /// </summary>\n        public bool Intersects(Triangle t)\n        {\n            if (t.A.BelongsTo(this) || t.B.BelongsTo(this) || t.C.BelongsTo(this))\n            {\n                return true;\n            }\n\n            foreach (Triangle bt in this.ListOfTriangles)\n            {\n                if (bt.Intersects(t)) return true;\n            }\n\n            return false;\n        }\n\n        /// <summary>\n        /// Check intersection of two boxes (only for AABB boxes, no check is performed for speed)\n        /// </summary>\n        public bool Intersects(Box3d box)\n        {\n            bool x = Abs(this.Center.X - box.Center.X) <= 0.5 * (this.L1 + box.L1) ? true : false;\n            bool y = Abs(this.Center.Y - box.Center.Y) <= 0.5 * (this.L2 + box.L2) ? true : false;\n            bool z = Abs(this.Center.Z - box.Center.Z) <= 0.5 * (this.L3 + box.L3) ? true : false;\n\n            return x && y && z;\n        }\n\n        private object _line_intersection(Line3d l, double t0, double t1)\n        {\n            // Smith's algorithm:\n            // \"An Efficient and Robust Ray–Box Intersection Algorithm\"\n            // Amy Williams, Steve Barrus, R. Keith Morley, Peter Shirley\n            // https://people.csail.mit.edu/amy/papers/box-jgt.pdf\n\n            // Modified to allow tolerance based checks\n\n            // Relative tolerance ================================\n            if (!GeometRi3D.UseAbsoluteTolerance)\n            {\n                double tol = GeometRi3D.Tolerance;\n                GeometRi3D.Tolerance = tol * this.Diagonal;\n                GeometRi3D.UseAbsoluteTolerance = true;\n                object result = _line_intersection(l, t0, t1);\n                GeometRi3D.UseAbsoluteTolerance = false;\n                GeometRi3D.Tolerance = tol;\n                return result;\n            }\n            //====================================================\n\n            // Define local CS aligned with box\n            Coord3d local_CS = this.LocalCoord();\n\n            Point3d Pmin = this.P1.ConvertTo(local_CS);\n            Point3d Pmax = this.P7.ConvertTo(local_CS);\n\n            l = new Line3d(l.Point.ConvertTo(local_CS), l.Direction.ConvertTo(local_CS).Normalized);\n\n            double tmin, tmax, tymin, tymax, tzmin, tzmax;\n            double divx = 1 / l.Direction.X;\n            if (divx >= 0)\n            {\n                tmin = (Pmin.X - l.Point.X) * divx;\n                tmax = (Pmax.X - l.Point.X) * divx;\n            }\n            else\n            {\n                tmin = (Pmax.X - l.Point.X) * divx;\n                tmax = (Pmin.X - l.Point.X) * divx;\n            }\n\n            double divy = 1 / l.Direction.Y;\n            if (divy >= 0)\n            {\n                tymin = (Pmin.Y - l.Point.Y) * divy;\n                tymax = (Pmax.Y - l.Point.Y) * divy;\n            }\n            else\n            {\n                tymin = (Pmax.Y - l.Point.Y) * divy;\n                tymax = (Pmin.Y - l.Point.Y) * divy;\n            }\n\n            if (GeometRi3D.Greater(tmin, tymax) || GeometRi3D.Greater(tymin, tmax))\n                return null;\n            if (GeometRi3D.Greater(tymin, tmin))\n                tmin = tymin;\n            if (GeometRi3D.Smaller(tymax, tmax))\n                tmax = tymax;\n\n            double divz = 1 / l.Direction.Z;\n            if (divz >= 0)\n            {\n                tzmin = (Pmin.Z - l.Point.Z) * divz;\n                tzmax = (Pmax.Z - l.Point.Z) * divz;\n            }\n            else\n            {\n                tzmin = (Pmax.Z - l.Point.Z) * divz;\n                tzmax = (Pmin.Z - l.Point.Z) * divz;\n            }\n\n            if (GeometRi3D.Greater(tmin, tzmax) || GeometRi3D.Greater(tzmin, tmax))\n                return null;\n            if (GeometRi3D.Greater(tzmin, tmin))\n                tmin = tzmin;\n            if (GeometRi3D.Smaller(tzmax, tmax))\n                tmax = tzmax;\n\n            // Now check the overlapping portion of the segments\n            // This part is missing in the original algorithm\n            if (GeometRi3D.Greater(tmin, t1))\n                return null;\n            if (GeometRi3D.Smaller(tmax, t0))\n                return null;\n\n            if (GeometRi3D.Smaller(tmin, t0))\n                tmin = t0;\n            if (GeometRi3D.Greater(tmax, t1))\n                tmax = t1;\n\n            if (GeometRi3D.AlmostEqual(tmin, tmax))\n            {\n                return l.Point.Translate(tmin * l.Direction);\n            }\n            else\n            {\n                return new Segment3d(l.Point.Translate(tmin * l.Direction), l.Point.Translate(tmax * l.Direction));\n            }\n        }\n#endregion\n\n\n        /// <summary>\n        /// Local coordinate system with origin in box's center and aligned with box\n        /// </summary>\n        public Coord3d LocalCoord()\n        {\n            return _local_coord;\n        }\n\n        /// <summary>\n        /// Point on box (including interior points) closest to target point \"p\".\n        /// </summary>\n        public Point3d ClosestPoint(Point3d p)\n        {\n            Coord3d local_coord = this.LocalCoord();\n            p = p.ConvertTo(local_coord);\n            double x = GeometRi3D.Clamp(p.X, -_lx / 2, _lx / 2);\n            double y = GeometRi3D.Clamp(p.Y, -_ly / 2, _ly / 2);\n            double z = GeometRi3D.Clamp(p.Z, -_lz / 2, _lz / 2);\n\n            return new Point3d(x, y, z, local_coord);\n        }\n\n        /// <summary>\n        /// Point on axis aligned box (including interior points) closest to target point \"p\".\n        /// </summary>\n        public Point3d AABBClosestPoint(Point3d p)\n        {\n            p = p.ConvertToGlobal();\n            double x = GeometRi3D.Clamp(p.X, this._center.X - _lx / 2, this._center.X + _lx / 2);\n            double y = GeometRi3D.Clamp(p.Y, this._center.Y - _ly / 2, this._center.Y + _ly / 2);\n            double z = GeometRi3D.Clamp(p.Z, this._center.Z - _lz / 2, this._center.Z + _lz / 2);\n\n            return new Point3d(x, y, z);\n        }\n\n        /// <summary>\n        /// Distance from box to point (zero will be returned for point located inside box)\n        /// </summary>\n        public double DistanceTo(Point3d p)\n        {\n            return ClosestPoint(p).DistanceTo(p);\n        }\n\n        /// <summary>\n        /// Distance from axis aligned box to point (zero will be returned for point located inside box)\n        /// </summary>\n        public double AABBDistanceTo(Point3d p)\n        {\n            return AABBClosestPoint(p).DistanceTo(p);\n        }\n\n        /// <summary>\n        /// Shortest distance from box to sphere\n        /// </summary>\n        public double DistanceTo(Sphere s)\n        {\n            Point3d p = this.ClosestPoint(s._point);\n            double dist = p.DistanceTo(s._point);\n            return dist <= s.R ? 0.0 : dist - s.R;\n        }\n\n        /// <summary>\n        /// Shortest distance from box to circle\n        /// </summary>\n        public double DistanceTo(Circle3d c)\n        {\n            if (c._point.IsInside(this))\n            {\n                return 0;\n            }\n            double min_dist = Double.PositiveInfinity;\n            foreach (Triangle triangle in ListOfTriangles)\n            {\n                double dist = c.DistanceTo(triangle);\n                if (dist <= GeometRi3D.Tolerance) return 0;\n                if (dist < min_dist) min_dist = dist;\n            }\n            return min_dist;\n        }\n\n        /// <summary>\n        /// Intersection check between circle and box\n        /// </summary>\n        public bool Intersects(Circle3d c)\n        {\n            //if (c.Center.IsInside(this)) return true;\n            double dist = c._point.DistanceTo(this);\n            if (dist > c.R) return false;\n            if (dist < GeometRi3D.Tolerance) return true;\n\n            foreach (Triangle triangle in ListOfTriangles)\n            {\n                if (c.Intersects(triangle)) return true;\n            }\n            return false;\n        }\n\n        internal override int _PointLocation(Point3d p)\n        {\n            Coord3d coord = this.LocalCoord();\n            p = p.ConvertTo(coord);\n            if (GeometRi3D.UseAbsoluteTolerance)\n            {\n                if ( (Abs(p.X)-L1/2) <= GeometRi3D.Tolerance && (Abs(p.Y) - L2 / 2) <= GeometRi3D.Tolerance && (Abs(p.Z) - L3 / 2) <= GeometRi3D.Tolerance )\n                {\n                    if ( (Abs(p.X) - L1 / 2) < -GeometRi3D.Tolerance && (Abs(p.Y) - L2 / 2) < -GeometRi3D.Tolerance && (Abs(p.Z) - L3 / 2) < -GeometRi3D.Tolerance)\n                    {\n                        return 1; // Point is strictly inside box\n                    } else\n                    {\n                        return 0; // Point is on boundary\n                    }\n                } else\n                {\n                    return -1; // Point is outside\n                }\n            }\n            else\n            {\n                double tol = GeometRi3D.Tolerance;\n                GeometRi3D.Tolerance = tol * this.Diagonal;\n                GeometRi3D.UseAbsoluteTolerance = true;\n                int result = this._PointLocation(p);\n                GeometRi3D.UseAbsoluteTolerance = false;\n                GeometRi3D.Tolerance = tol;\n                return result;\n            }\n        }\n\n#region \"TranslateRotateReflect\"\n        /// <summary>\n        /// Translate box by a vector\n        /// </summary>\n        public Box3d Translate(Vector3d v)\n        {\n            return new Box3d(_center.Translate(v), _lx, _ly, _lz);\n        }\n\n        /// <summary>\n        /// Rotate box around point 'p' as a rotation center.\n        /// </summary>\n        public Box3d Rotate(Rotation r, Point3d p)\n        {\n            Point3d new_center = r.ToRotationMatrix * (this._center - p) + p;\n            Rotation new_rotation = r * this.Orientation;\n            return new Box3d(new_center, _lx, _ly, _lz, new_rotation);\n        }\n\n        /// <summary>\n        /// Reflect box in given point\n        /// <para>The order of corner points will be changed during reflection operation.</para>\n        /// </summary>\n        public virtual Box3d ReflectIn(Point3d p)\n        {\n            Point3d new_center = this.Center.ReflectIn(p);\n            return new Box3d(new_center, _lx, _ly, _lz, this._r);\n        }\n\n        /// <summary>\n        /// Reflect box in given line\n        /// <para>The order of corner points will be changed during reflection operation.</para>\n        /// </summary>\n        public virtual Box3d ReflectIn(Line3d l)\n        {\n            Point3d new_center = this.Center.ReflectIn(l);\n            Rotation r = new GeometRi.Rotation(l.Direction, PI);\n            Rotation new_rotation = r * this.Orientation;\n            return new Box3d(new_center, _lx, _ly, _lz, new_rotation);\n        }\n\n        /// <summary>\n        /// Reflect box in given plane\n        /// <para>The order of corner points will be changed during reflection operation.</para>\n        /// </summary>\n        public virtual Box3d ReflectIn(Plane3d s)\n        {\n            Point3d new_center = this.Center.ReflectIn(s);\n            Vector3d nV1 = this.V1.ReflectIn(s);\n            Vector3d nV2 = this.V2.ReflectIn(s);\n            Coord3d coord = new Coord3d(new_center, nV1, nV2);\n            Rotation new_rotation = new Rotation(coord);\n            return new Box3d(new_center, _lx, _ly, _lz, new_rotation);\n        }\n\n        /// <summary>\n        /// Scale box relative to given point\n        /// </summary>\n        public virtual Box3d Scale(double scale, Point3d scaling_center)\n        {\n            Point3d new_center = scaling_center + scale * (this.Center - scaling_center);\n            return new Box3d(new_center, scale * _lx, scale * _ly, scale * _lz, this._r);\n        }\n\n        #endregion\n\n\n        /// <summary>\n        /// Determines whether two objects are equal.\n        /// </summary>\n        public override bool Equals(object obj)\n        {\n            if (obj == null || (!object.ReferenceEquals(this.GetType(), obj.GetType())))\n            {\n                return false;\n            }\n            Box3d b = (Box3d)obj;\n\n            if (GeometRi3D.UseAbsoluteTolerance)\n            {\n                return this.Center == b.Center && _r == b.Orientation &&\n                       GeometRi3D.AlmostEqual(L1, b.L1) &&\n                       GeometRi3D.AlmostEqual(L2, b.L2) &&\n                       GeometRi3D.AlmostEqual(L3, b.L3);\n            }\n            else\n            {\n                double tol = GeometRi3D.Tolerance;\n                GeometRi3D.Tolerance = tol * this.Diagonal;\n                GeometRi3D.UseAbsoluteTolerance = true;\n                bool result = this.Equals(b);\n                GeometRi3D.UseAbsoluteTolerance = false;\n                GeometRi3D.Tolerance = tol;\n                return result;\n            }\n\n        }\n\n        /// <summary>\n        /// Returns the hashcode for the object.\n        /// </summary>\n        public override int GetHashCode()\n        {\n            int hash_code = GeometRi3D.HashFunction(_lx.GetHashCode(), _ly.GetHashCode(), _lz.GetHashCode());\n            return GeometRi3D.HashFunction(_center.GetHashCode(), _r.GetHashCode(), hash_code);\n        }\n\n        /// <summary>\n        /// String representation of an object in global coordinate system.\n        /// </summary>\n        public override string ToString()\n        {\n            return ToString(Coord3d.GlobalCS);\n        }\n\n        /// <summary>\n        /// String representation of an object in reference coordinate system.\n        /// </summary>\n        public string ToString(Coord3d coord)\n        {\n            string nl = System.Environment.NewLine;\n\n            if (coord == null) { coord = Coord3d.GlobalCS; }\n            Point3d p = _center.ConvertTo(coord);\n\n            string str = string.Format(\"Box3d (reference coord.sys. \") + coord.Name + \"):\" + nl;\n            str += string.Format(\"Center -> ({0,10:g5}, {1,10:g5}, {2,10:g5})\", p.X, p.Y, p.Z) + nl;\n            str += string.Format(\"Lx, Ly, Lz -> ({0,10:g5}, {1,10:g5}, {2,10:g5})\", _lx, _ly, _lz) + nl;\n            str += _r.ToString(coord);\n            return str;\n        }\n\n        // Operators overloads\n        //-----------------------------------------------------------------\n        public static bool operator ==(Box3d b1, Box3d b2)\n        {\n            if (object.ReferenceEquals(b1, null))\n                return object.ReferenceEquals(b2, null);\n            return b1.Equals(b2);\n        }\n        public static bool operator !=(Box3d b1, Box3d b2)\n        {\n            if (object.ReferenceEquals(b1, null))\n                return !object.ReferenceEquals(b2, null);\n            return !b1.Equals(b2);\n        }\n    }\n}\n"
  },
  {
    "path": "GeometRi/Circle3D.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Drawing;\nusing static System.Math;\n\nnamespace GeometRi\n{\n    /// <summary>\n    /// Circle in 3D space defined by center point, radius and normal vector.\n    /// </summary>\n#if NET20_OR_GREATER\n    [Serializable]\n#endif\n    public class Circle3d : FiniteObject, IPlanarObject, IFiniteObject\n    {\n\n        internal Point3d _point;\n        private double _r;\n        internal Vector3d _normal;\n\n        /// <summary>\n        /// Initializes circle instance using center point, radius and normal vector.\n        /// </summary>\n        public Circle3d(Point3d Center, double Radius, Vector3d Normal)\n        {\n            _point = Center.Copy();\n            _r = Radius;\n            _normal = Normal.Normalized;\n        }\n\n        /// <summary>\n        /// Initializes circle passing through three points.\n        /// </summary>\n        public Circle3d(Point3d p1, Point3d p2, Point3d p3)\n        {\n            Vector3d v1 = new Vector3d(p1, p2);\n            Vector3d v2 = new Vector3d(p1, p3);\n            if (v1.Cross(v2).Norm < GeometRi3D.Tolerance)\n            {\n                throw new Exception(\"Collinear points\");\n            }\n\n            Coord3d CS = new Coord3d(p1, v1, v2);\n            Point3d a1 = p1.ConvertTo(CS);\n            Point3d a2 = p2.ConvertTo(CS);\n            Point3d a3 = p3.ConvertTo(CS);\n\n            double d1 = Math.Pow(a1.X, 2) + Math.Pow(a1.Y, 2);\n            double d2 = Math.Pow(a2.X, 2) + Math.Pow(a2.Y, 2);\n            double d3 = Math.Pow(a3.X, 2) + Math.Pow(a3.Y, 2);\n            double f = 2.0 * (a1.X * (a2.Y - a3.Y) - a1.Y * (a2.X - a3.X) + a2.X * a3.Y - a3.X * a2.Y);\n\n            double X = (d1 * (a2.Y - a3.Y) + d2 * (a3.Y - a1.Y) + d3 * (a1.Y - a2.Y)) / f;\n            double Y = (d1 * (a3.X - a2.X) + d2 * (a1.X - a3.X) + d3 * (a2.X - a1.X)) / f;\n            //_point = (new Point3d(X, Y, 0, CS)).ConvertTo(p1.Coord);\n            _point = new Point3d(X, Y, 0, CS);\n            _point = _point.ConvertTo(p1.Coord);\n            _r = Sqrt((X - a1.X) * (X - a1.X) + (Y - a1.Y) * (Y - a1.Y));\n            _normal = v1.Cross(v2).Normalized;\n\n        }\n\n        /// <summary>\n        /// Creates copy of the object\n        /// </summary>\n        public Circle3d Copy()\n        {\n            return new Circle3d(_point, _r, _normal);\n        }\n\n        /// <summary>\n        /// Center of the circle\n        /// </summary>\n        public Point3d Center\n        {\n            get { return _point; }\n            set { _point = value.Copy(); }\n        }\n\n        /// <summary>\n        /// X component of the circles' center\n        /// </summary>\n        public double X\n        {\n            get { return _point.X; }\n            //set { _point.X = value; }\n        }\n\n        /// <summary>\n        /// Y component of the circles' center\n        /// </summary>\n        public double Y\n        {\n            get { return _point.Y; }\n            //set { _point.Y = value; }\n        }\n\n        /// <summary>\n        /// Z component of the circles' center\n        /// </summary>\n        public double Z\n        {\n            get { return _point.Z; }\n            //set { _point.Z = value; }\n        }\n\n        /// <summary>\n        /// Radius of the circle\n        /// </summary>\n        public double R\n        {\n            get { return _r; }\n            set { _r = value; }\n        }\n\n        /// <summary>\n        /// Normal of the circle\n        /// </summary>\n        public Vector3d Normal\n        {\n            get { return _normal; }\n            set { _normal = value.Copy(); }\n        }\n\n        public bool IsOriented\n        {\n            get { return false; }\n        }\n\n        public double Perimeter\n        {\n            get { return 2 * PI * _r; }\n        }\n\n        /// <summary>\n        /// Area of the circle.\n        /// </summary>\n        public double Area\n        {\n            get { return PI * _r * _r; }\n        }\n\n        /// <summary>\n        /// Convert circle to ellipse object.\n        /// </summary>\n        public Ellipse ToEllipse\n        {\n            get\n            {\n                Vector3d v1 = _r * _normal.OrthogonalVector.Normalized;\n                Vector3d v2 = _r * (_normal.Cross(v1)).Normalized;\n                return new Ellipse(_point, v1, v2);\n            }\n        }\n\n        /// <summary>\n        /// Convert circle to plane object.\n        /// </summary>\n        public Plane3d ToPlane\n        {\n            get\n            {\n                return new Plane3d(_point, _normal);\n            }\n        }\n\n        #region \"ParallelMethods\"\n        /// <summary>\n        /// Check if two objects are parallel\n        /// </summary>\n        public bool IsParallelTo(ILinearObject obj)\n        {\n            return this.Normal.IsOrthogonalTo(obj.Direction);\n        }\n\n        /// <summary>\n        /// Check if two objects are NOT parallel\n        /// </summary>\n        public bool IsNotParallelTo(ILinearObject obj)\n        {\n            return !this.Normal.IsOrthogonalTo(obj.Direction);\n        }\n\n        /// <summary>\n        /// Check if two objects are orthogonal\n        /// </summary>\n        public bool IsOrthogonalTo(ILinearObject obj)\n        {\n            return this.Normal.IsParallelTo(obj.Direction);\n        }\n\n        /// <summary>\n        /// Check if two objects are parallel\n        /// </summary>\n        public bool IsParallelTo(IPlanarObject obj)\n        {\n            return this.Normal.IsParallelTo(obj.Normal);\n        }\n\n        /// <summary>\n        /// Check if two objects are NOT parallel\n        /// </summary>\n        public bool IsNotParallelTo(IPlanarObject obj)\n        {\n            return this.Normal.IsNotParallelTo(obj.Normal);\n        }\n\n        /// <summary>\n        /// Check if two objects are orthogonal\n        /// </summary>\n        public bool IsOrthogonalTo(IPlanarObject obj)\n        {\n            return this.Normal.IsOrthogonalTo(obj.Normal);\n        }\n\n        /// <summary>\n        /// Check if two objects are coplanar\n        /// </summary>\n        public bool IsCoplanarTo(IPlanarObject obj)\n        {\n            return GeometRi3D._coplanar(this, obj);\n        }\n\n        /// <summary>\n        /// Check if two objects are coplanar\n        /// </summary>\n        public bool IsCoplanarTo(ILinearObject obj)\n        {\n            return GeometRi3D._coplanar(this, obj);\n        }\n        #endregion\n\n        #region \"BoundingBox\"\n        /// <summary>\n        /// Return minimum bounding box.\n        /// </summary>\n        public Box3d MinimumBoundingBox\n        {\n            get\n            {\n                Vector3d v1 = this.Normal.OrthogonalVector.Normalized;\n                Vector3d v2 = this.Normal.Cross(v1).Normalized;\n                Vector3d v3 = this.Normal;\n                Matrix3d m = new Matrix3d(v1, v2, v3);\n                Rotation r = new Rotation(m.Transpose());\n                return new Box3d(_point, 2.0 * _r, 2.0 * _r, 0, r);\n            }\n        }\n\n        /// <summary>\n        /// Return Bounding Box in given coordinate system.\n        /// </summary>\n        public Box3d BoundingBox(Coord3d coord = null)\n        {\n            coord = (coord == null) ? Coord3d.GlobalCS : coord;\n            Vector3d v = _normal.ConvertTo(coord);\n\n            double s1 = _r * Sqrt(1 - v.X * v.X);\n            double s2 = _r * Sqrt(1 - v.Y * v.Y);\n            double s3 = _r * Sqrt(1 - v.Z * v.Z);\n\n            return new Box3d(_point, 2 * s1, 2 * s2, 2 * s3, coord);\n        }\n\n        /// <summary>\n        /// Return Axis Aligned Bounding Box (AABB).\n        /// </summary>\n        public AABB AABB()\n        {\n            Vector3d v = _normal.ConvertToGlobal();\n\n            double s1 = _r * Sqrt(1 - v.X * v.X);\n            double s2 = _r * Sqrt(1 - v.Y * v.Y);\n            double s3 = _r * Sqrt(1 - v.Z * v.Z);\n\n            return new AABB(_point, 2 * s1, 2 * s2, 2 * s3);\n        }\n\n        /// <summary>\n        /// Return bounding sphere.\n        /// </summary>\n        public Sphere BoundingSphere\n        {\n            get { return new Sphere(_point, _r); }\n\n        }\n\n        /// <summary>\n        /// Check if circle is located inside box with tolerance defined by global tolerance property (GeometRi3D.Tolerance).\n        /// </summary>\n        public bool IsInside(Box3d box)\n        {\n            // Relative tolerance ================================\n            if (!GeometRi3D.UseAbsoluteTolerance)\n            {\n                double tol = GeometRi3D.Tolerance;\n                GeometRi3D.Tolerance = tol * this.R;\n                GeometRi3D.UseAbsoluteTolerance = true;\n                bool result = this.IsInside(box);\n                GeometRi3D.UseAbsoluteTolerance = false;\n                GeometRi3D.Tolerance = tol;\n                return result;\n            }\n            //====================================================\n\n            if (!this._point.IsInside(box)) return false;\n\n            Coord3d local_coord = box.LocalCoord();\n            Box3d circle_box = this.BoundingBox(local_coord);\n            Point3d p = _point.ConvertTo(local_coord);\n\n            if (box.L1 / 2 - (Abs(p.X) + circle_box.L1 / 2) < GeometRi3D.Tolerance) return false;\n            if (box.L2 / 2 - (Abs(p.Y) + circle_box.L2 / 2) < GeometRi3D.Tolerance) return false;\n            if (box.L3 / 2 - (Abs(p.Z) + circle_box.L3 / 2) < GeometRi3D.Tolerance) return false;\n\n            return true;\n        }\n\n        #endregion\n\n        /// <summary>\n        /// Returns point on circle for given parameter 't' (0 &lt;= t &lt; 2Pi)\n        /// </summary>\n        public Point3d ParametricForm(double t)\n        {\n            // Get two orthogonal coplanar vectors\n            Vector3d v1 = _r * _normal.OrthogonalVector.Normalized;\n            Vector3d v2 = _r * (_normal.Cross(v1)).Normalized;\n            return _point + v1 * Cos(t) + v2 * Sin(t);\n        }\n\n        #region \"DistanceMethods\"\n        /// <summary>\n        /// Distance from circle to plane\n        /// </summary>\n        public double DistanceTo(Plane3d s)\n        {\n            double center_distance = Math.Abs((this._point - s._point).Dot(s._normal));\n            double sin_angle = this._normal.Cross(s._normal).Norm;\n            double delta = Abs(this.R * sin_angle);\n\n            if (delta < center_distance)\n            {\n                return center_distance - delta;\n            }\n            else\n            {\n                return 0;\n            }\n        }\n\n        /// <summary>\n        /// Shortest distance between plane and circle\n        /// <para> The output points may be not unique in case of parallel or intersecting objects.</para>\n        /// </summary>\n        /// <param name=\"p\">Target plane</param>\n        /// <param name=\"point_on_circle\">Closest point on circle</param>\n        /// <param name=\"point_on_plane\">Closest point on plane</param>\n        public double DistanceTo(Plane3d p, out Point3d point_on_circle, out Point3d point_on_plane)\n        {\n            if (this.IsParallelTo(p))\n            {\n                point_on_circle = this.Center;\n                point_on_plane = point_on_circle.ProjectionTo(p);\n                return point_on_circle.DistanceTo(point_on_plane);\n            }\n\n            Vector3d v1 = this._normal.Cross(p.Normal);\n            Vector3d v2 = this._normal.Cross(v1);\n\n            double d = (p._point - this._point).Dot(p._normal) / (p._normal * v2);\n            Point3d intersection_point = this._point.Translate(d * v2);\n\n            if (intersection_point.DistanceTo(this.Center) <= this.R)\n            {\n                point_on_circle = intersection_point;\n                point_on_plane = intersection_point;\n                return 0;\n            }\n            else\n            {\n                point_on_circle = this._point.Translate(Sign(d) * this.R * v2.Normalized);\n                point_on_plane = point_on_circle.ProjectionTo(p);\n                return point_on_circle.DistanceTo(point_on_plane);\n\n                //Point3d delta = point_on_circle - p._point;\n                //double dist = delta.Dot(p._normal);\n                //point_on_plane = point_on_circle - dist * p._normal;\n                //return dist;\n\n            }\n        }\n\n        /// <summary>\n        /// Shortest distance from point to circle (including interior points)\n        /// </summary>\n        public double DistanceTo(Point3d p)\n        {\n            Point3d delta = p - this._point;\n            Point3d Q = p.Subtract(this._normal, delta.Dot(this._normal));\n            double dist = this._point.DistanceTo(Q);\n            if (dist < this._r)\n            {\n                return Q.DistanceTo(p); ;\n            }\n            else\n            {\n                Point3d K = this._point + this._r / dist * (Q - this._point);\n                return K.DistanceTo(p); ;\n            }\n        }\n\n        /// <summary>\n        /// Point on circle (including interior points) closest to target point \"p\".\n        /// </summary>\n        public Point3d ClosestPoint(Point3d p)\n        {\n            Point3d delta = p - this._point;\n            Point3d Q = p.Subtract(this._normal, delta.Dot(this._normal));\n            double dist = this._point.DistanceTo(Q);\n            if (dist < this._r)\n            {\n                return Q;\n            }\n            else\n            {\n                return this._point + this._r / dist * (Q - this._point);\n            }\n        }\n\n        /// <summary>\n        /// Point on circle (excluding interior points) closest to target point \"p\".\n        /// </summary>\n        public Point3d ClosestPointOnBoundary(Point3d p)\n        {\n            Point3d delta = p - this._point;\n            Point3d Q = p.Subtract(this._normal, delta.Dot(this._normal));\n            double dist = this._point.DistanceTo(Q);\n            return this._point + this._r / dist * (Q - this._point);\n        }\n\n        /// <summary>\n        /// Shortest distance between two circles (including interior points) (approximate solution)\n        /// <para> Default tolerance for numerical solution: GeometRi3D.DefaultTolerance.</para>\n        /// </summary>\n        /// <param name=\"c\">Target circle</param>\n        public double DistanceTo(Circle3d c)\n        {\n            return DistanceTo(c, GeometRi3D.DefaultTolerance);\n        }\n\n        /// <summary>\n        /// Shortest distance between two circles (including interior points) (approximate solution)\n        /// </summary>\n        /// <param name=\"c\">Target circle</param>\n        /// <param name=\"tolerance\">Tolerance for numerical solution, default GeometRi3D.DefaultTolerance</param>\n        public double DistanceTo(Circle3d c, double tolerance)\n        {\n            double dist;\n            if (GeometRi3D.AlmostEqual(Abs(this._normal * c._normal), 1.0))\n            {\n                Point3d projection = c._point.ProjectionTo(this.ToPlane);\n                dist = projection.DistanceTo(this._point);\n                double vdist = projection.DistanceTo(c._point);\n                if (dist < this.R + c.R)\n                {\n                    return vdist;\n                }\n                else\n                {\n                    return Sqrt((dist - this.R - c.R) * (dist - this.R - c.R) + vdist * vdist);\n                }\n            }\n\n            double tol = GeometRi3D.Tolerance;\n            bool mode = GeometRi3D.UseAbsoluteTolerance;\n            GeometRi3D.Tolerance = GeometRi3D.DefaultTolerance;\n            GeometRi3D.UseAbsoluteTolerance = true;\n\n            //object obj = this.IntersectionWith(c);\n            if (_circle_circle_intersection_check_2(c))\n            {\n                // Restore initial state\n                GeometRi3D.UseAbsoluteTolerance = mode;\n                GeometRi3D.Tolerance = tol;\n\n                return 0;\n            }\n\n            Point3d p_on_circle, p_on_plane;\n            dist = this.DistanceTo(c.ToPlane, out p_on_circle, out p_on_plane);\n            if (p_on_plane.DistanceTo(c._point) <= c.R)\n            {\n                // Restore initial state\n                GeometRi3D.UseAbsoluteTolerance = mode;\n                GeometRi3D.Tolerance = tol;\n                return dist;\n            }\n\n            dist = c.DistanceTo(this.ToPlane, out p_on_circle, out p_on_plane);\n            if (p_on_plane.DistanceTo(this._point) <= this.R)\n            {\n                // Restore initial state\n                GeometRi3D.UseAbsoluteTolerance = mode;\n                GeometRi3D.Tolerance = tol;\n                return dist;\n            }\n\n            dist = _distance_circle_to_circle(this, c, out Point3d p1, out Point3d p2, tolerance);\n            // Restore initial state\n            GeometRi3D.UseAbsoluteTolerance = mode;\n            GeometRi3D.Tolerance = tol;\n            return dist;\n\n        }\n\n        /// <summary>\n        /// Shortest distance between two circles (including interior points) (approximate solution)\n        /// <para> The output points may be not unique in case of parallel or intersecting circles.</para>\n        /// <para> Default tolerance for numerical solution: GeometRi3D.DefaultTolerance.</para>\n        /// </summary>\n        /// <param name=\"c\">Target circle</param>\n        /// <param name=\"p1\">Closest point on source circle</param>\n        /// <param name=\"p2\">Closest point on target circle</param>\n        public double DistanceTo(Circle3d c, out Point3d p1, out Point3d p2)\n        {\n            return DistanceTo(c, out p1, out p2, GeometRi3D.DefaultTolerance);\n        }\n\n        /// <summary>\n        /// Shortest distance between two circles (including interior points) (approximate solution)\n        /// <para> The output points may be not unique in case of parallel or intersecting circles.</para>\n        /// </summary>\n        /// <param name=\"c\">Target circle</param>\n        /// <param name=\"p1\">Closest point on source circle</param>\n        /// <param name=\"p2\">Closest point on target circle</param>\n        /// <param name=\"tolerance\">Tolerance for numerical solution, default GeometRi3D.DefaultTolerance</param>\n        public double DistanceTo(Circle3d c, out Point3d p1, out Point3d p2, double tolerance)\n        {\n            double dist;\n            if (GeometRi3D.AlmostEqual(Abs(this._normal * c._normal), 1.0))\n            {\n                Point3d projection = c._point.ProjectionTo(this.ToPlane);\n                dist = projection.DistanceTo(this._point);\n                double vdist = projection.DistanceTo(c._point);\n                if (dist < this.R + c.R)\n                {\n                    if (projection.BelongsTo(this))\n                    {\n                        p1 = projection;\n                        p2 = c.Center;\n                    }\n                    else\n                    {\n                        p1 = this._point.Translate(this.R * new Vector3d(this._point, projection).Normalized);\n                        p2 = p1.ProjectionTo(c.ToPlane);\n                    }\n                    return vdist;\n                }\n                else\n                {\n                    Vector3d v = new Vector3d(this._point, projection).Normalized;\n                    p1 = this._point.Translate(this.R * v);\n                    p2 = c._point.Translate(-c.R * v);\n                    return Sqrt((dist - this.R - c.R) * (dist - this.R - c.R) + vdist * vdist);\n                }\n            }\n\n            double tol = GeometRi3D.Tolerance;\n            bool mode = GeometRi3D.UseAbsoluteTolerance;\n            GeometRi3D.Tolerance = GeometRi3D.DefaultTolerance;\n            GeometRi3D.UseAbsoluteTolerance = true;\n\n            object obj = this.IntersectionWith(c);\n            if (obj != null)\n            {\n                // Restore initial state\n                GeometRi3D.UseAbsoluteTolerance = mode;\n                GeometRi3D.Tolerance = tol;\n\n                if (obj.GetType() == typeof(Point3d))\n                {\n                    p1 = (Point3d)obj;\n                    p2 = (Point3d)obj;\n                }\n                else if (obj.GetType() == typeof(Segment3d))\n                {\n                    p1 = ((Segment3d)obj).P1;\n                    p2 = ((Segment3d)obj).P1;\n                }\n                else\n                {\n                    p1 = ((Circle3d)obj).Center;\n                    p2 = ((Circle3d)obj).Center;\n                }\n\n                return 0;\n            }\n\n            dist = this.DistanceTo(c.ToPlane, out p1, out p2);\n            if (p2.DistanceTo(c._point) <= c.R)\n            {\n                // Restore initial state\n                GeometRi3D.UseAbsoluteTolerance = mode;\n                GeometRi3D.Tolerance = tol;\n                return dist;\n            }\n\n            dist = c.DistanceTo(this.ToPlane, out p2, out p1);\n            if (p1.DistanceTo(this._point) <= this.R)\n            {\n                // Restore initial state\n                GeometRi3D.UseAbsoluteTolerance = mode;\n                GeometRi3D.Tolerance = tol;\n                return dist;\n            }\n\n            dist = _distance_circle_to_circle(this, c, out p1, out p2, tolerance);\n\n            // Restore initial state\n            GeometRi3D.UseAbsoluteTolerance = mode;\n            GeometRi3D.Tolerance = tol;\n\n            return dist;\n\n        }\n\n\n        /// <summary>\n        /// Check if distance between two circles is greater than threshold\n        /// </summary>\n        public bool DistanceGreater(Circle3d c, double threshold, double tolerance)\n        {\n\n            // Relative tolerance ================================\n            if (!GeometRi3D.UseAbsoluteTolerance)\n            {\n                double tol = GeometRi3D.Tolerance;\n                GeometRi3D.Tolerance = tol * Max(this.R, c.R);\n                GeometRi3D.UseAbsoluteTolerance = true;\n                bool result = this.DistanceGreater(c, threshold, tolerance);\n                GeometRi3D.UseAbsoluteTolerance = false;\n                GeometRi3D.Tolerance = tol;\n                return result;\n            }\n            //====================================================\n\n            // Early exit (separated circles)\n            double d = this._point.DistanceTo(c._point);\n            if (d > this.R + c.R + GeometRi3D.Tolerance + threshold)\n                return true;\n\n            if (GeometRi3D.AlmostEqual(Abs(this._normal * c._normal), 1.0))\n            {\n                if (this._point.BelongsTo(new Plane3d(c._point, c._normal)))\n                {\n                    // Coplanar objects\n                    if (d <= this.R + c.R + GeometRi3D.Tolerance + threshold)\n                    {\n                        return false;\n                    }\n                    else\n                    {\n                        return true;\n                    }\n                }\n                else\n                {\n                    // parallel objects\n                    return this.DistanceTo(c, out Point3d p1, out Point3d p2, tolerance) > threshold;\n                }\n            }\n            else\n            {\n                // Check 3D intersection\n                //Vector3d v = new Vector3d(this._point, c._point);\n                Point3d v = c._point - this._point;\n                //double this_norm = this._normal.Norm;\n                //double c_norm = c._normal.Norm;\n                double this_norm = 1;\n                double c_norm = 1;\n\n                double cos_angle1 = v.Dot(this._normal) / this_norm / d;\n                double delta1 = Abs(d * cos_angle1);\n\n                double sin_angle2 = this._normal.Cross(c._normal).Norm / this_norm / c_norm;\n                double delta2 = Abs(this.R * sin_angle2);\n\n                if (delta1 > delta2 + threshold) return true;\n\n                cos_angle1 = v.Dot(c._normal) / c_norm / d;\n                delta1 = Abs(d * cos_angle1);\n                delta2 = Abs(c.R * sin_angle2);\n\n                if (delta1 > delta2 + threshold) return true;\n\n                return this.DistanceTo(c, tolerance) > threshold;\n\n            }\n        }\n\n        private double _distance_circle_to_circle_new(Circle3d c1, Circle3d c2, out Point3d p1, out Point3d p2, double tol)\n        {\n            double dist_prev = double.PositiveInfinity;\n            int max_iter = 100;\n            p1 = c1.ClosestPointOnBoundary(c2.Center);\n            p2 = c2.ClosestPointOnBoundary(p1);\n            double dist = p1.DistanceTo(p2);\n\n            int iter = 0;\n            while (iter < max_iter)\n            {\n                dist_prev = dist;\n                p1 = c1.ClosestPointOnBoundary(p2);\n                p2 = c2.ClosestPointOnBoundary(p1);\n                dist = p1.DistanceTo(p2);\n\n                if (Math.Abs(dist - dist_prev) < tol)\n                {\n                    return dist;\n                }\n\n                iter++;\n            }\n            return dist;\n\n        }\n\n        private double _distance_circle_to_circle(Circle3d c1, Circle3d c2, out Point3d p1, out Point3d p2, double tol)\n        // Use quadratic interpolation to find closest point on one circle to other\n        // p1 and p2 - closest points on both circles\n        {\n            //double tol = GeometRi3D.DefaultTolerance;\n            double d1 = 1e20;\n            double t1 = 0;\n            Point3d p;\n\n            // Prepare data for parametric form for circle \"c1\".\n            // _point + v1.ToPoint * Cos(t) + v2.ToPoint * Sin(t);\n            // Get two orthogonal vectors coplanar \"c1\"\n            Vector3d v1 = c1._r * c1._normal.OrthogonalVector.Normalized;\n            Vector3d v2 = c1._r * (c1._normal.Cross(v1)).Normalized;\n            Point3d pf1 = v1.ToPoint.ConvertTo(c1._point.Coord);\n            Point3d pf2 = v2.ToPoint.ConvertTo(c1._point.Coord);\n\n            for (int i = 0; i < 16; i++)\n            {\n                double t = i * Math.PI / 8;\n                p = c1._point + pf1 * Cos(t) + pf2 * Sin(t);\n                double dist = p.DistanceTo(c2);\n                if (dist < d1)\n                {\n                    d1 = dist;\n                    t1 = t;\n                }\n            }\n            double t2 = t1 - Math.PI / 8;\n            p = c1._point + pf1 * Cos(t2) + pf2 * Sin(t2);\n            double d2 = p.DistanceTo(c2);\n            double t3 = t1 + Math.PI / 8;\n            p = c1._point + pf1 * Cos(t3) + pf2 * Sin(t3);\n            double d3 = p.DistanceTo(c2);\n\n            int iter = 0;\n            bool flag = false;\n            while ((d2 - d1 > tol || d3 - d1 > tol)  && d1 > tol)\n            {\n                if (++iter > 100) break;\n\n                double ax = 2.0 * d1 / (t1 - t2) / (t1 - t3);\n                double aa = 0.5 * ax * (t2 + t3);\n                double bx = 2.0 * d2 / (t2 - t1) / (t2 - t3);\n                double bb = 0.5 * bx * (t1 + t3);\n                double cx = 2.0 * d3 / (t3 - t1) / (t3 - t2);\n                double cc = 0.5 * cx * (t1 + t2);\n\n                double t = (aa + bb + cc) / (ax + bx + cx);\n                p = c1._point + pf1 * Cos(t) + pf2 * Sin(t);\n                double d = p.DistanceTo(c2);\n\n                if (d > d1)\n                // Possible special case, non-smooth function ( f(t)=|t| )\n                {\n                    flag = true;\n                    break;\n                }\n\n                if (t>t2 & t<t1)\n                {\n                    t3 = t1; d3 = d1;\n                }\n                else\n                {\n                    t2 = t1; d2 = d1;\n                }\n                t1 = t; d1 = d;\n            }\n\n            if (flag)\n            // Possible special case, non-smooth function ( f(t)=|t| )\n            {\n                while ((d2 - d1 > tol || d3 - d1 > tol) && d1 > tol)\n                {\n                    if (++iter > 100) break;\n\n                    double t = (t2+t1) / 2;\n                    p = c1._point + pf1 * Cos(t) + pf2 * Sin(t);\n                    double d = p.DistanceTo(c2);\n                    if (d < d1)\n                    {\n                        t3 = t1; d3 = d1;\n                        t1 = t;  d1 = d;\n                    }\n                    else\n                    {\n                        t2 = t; d2 = d;\n                    }\n\n                    t = (t3 + t1) / 2;\n                    p = c1._point + pf1 * Cos(t) + pf2 * Sin(t);\n                    d = p.DistanceTo(c2);\n                    if (d < d1)\n                    {\n                        t2 = t1; d2 = d1;\n                        t1 = t; d1 = d;\n                    }\n                    else\n                    {\n                        t3 = t; d3 = d;\n                    }\n                }\n            }\n\n            p1 = c1._point + pf1 * Cos(t1) + pf2 * Sin(t1);\n            p2 = c2.ClosestPoint(p1);\n            return d1;\n        }\n\n        /// <summary>\n        /// Shortest distance between circle and sphere (including interior points) (approximate solution)\n        /// </summary>\n        public double DistanceTo(Sphere s)\n        {\n            return DistanceTo(s, GeometRi3D.DefaultTolerance);\n        }\n\n        /// <summary>\n        /// Shortest distance between circle and sphere (including interior points) (approximate solution)\n        /// </summary>\n        /// <param name=\"s\">Target sphere</param>\n        /// <param name=\"tolerance\">Tolerance for numerical solution, default GeometRi3D.DefaultTolerance</param>\n        public double DistanceTo(Sphere s, double tolerance)\n        {\n            Plane3d p = this.ToPlane;\n            if (s.Center.ProjectionTo(p).BelongsTo(this))\n            {\n                return s.DistanceTo(p);\n            }\n\n            if (this.Intersects(s))\n                return 0;\n\n            Point3d p1, p2;\n            double dist = _distance_circle_to_sphere(this, s, out p1, out p2, tolerance);\n\n            return dist;\n        }\n\n        /// <summary>\n        /// Shortest distance between circle and sphere (including interior points) (approximate solution)\n        /// <para> The output points may be not unique in case of intersecting objects.</para>\n        /// <para> Default tolerance for numerical solution: GeometRi3D.DefaultTolerance.</para>\n        /// </summary>\n        /// <param name=\"s\">Target sphere</param>\n        /// <param name=\"p1\">Closest point on circle</param>\n        /// <param name=\"p2\">Closest point on sphere</param>\n        public double DistanceTo(Sphere s, out Point3d p1, out Point3d p2)\n        {\n            return DistanceTo(s, out p1, out p2, GeometRi3D.DefaultTolerance);\n        }\n\n        /// <summary>\n        /// Shortest distance between circle and sphere (including interior points) (approximate solution)\n        /// <para> The output points may be not unique in case of intersecting objects.</para>\n        /// </summary>\n        /// <param name=\"s\">Target sphere</param>\n        /// <param name=\"p1\">Closest point on circle</param>\n        /// <param name=\"p2\">Closest point on sphere</param>\n        /// <param name=\"tolerance\">Tolerance for numerical solution, default GeometRi3D.DefaultTolerance</param>\n        public double DistanceTo(Sphere s, out Point3d p1, out Point3d p2, double tolerance)\n        {\n            Plane3d p = this.ToPlane;\n            if (s.Center.ProjectionTo(p).BelongsTo(this))\n            {\n                p1 = s.Center.ProjectionTo(p);\n                if (s.Center == p1)\n                {\n                    p2 = s.Center.Translate(s.R * this.Normal);\n                }\n                else\n                {\n                    p2 = s.Center.Translate(s.R * new Vector3d(s.Center, p1).Normalized);\n                }\n                return s.DistanceTo(p);\n            }\n\n            if (this.Intersects(s))\n            {\n                Object obj = s.IntersectionWith(p);\n                if (obj.GetType() == typeof(Point3d))\n                {\n                    p1 = (Point3d)obj;\n                    p2 = p1;\n                }\n                else\n                {\n                    Circle3d c = (Circle3d)obj;\n                    p1 = this._point.Translate(this.R * new Vector3d(this._point, c._point).Normalized);\n                    p2 = c._point.Translate(c.R * new Vector3d(c._point, this._point).Normalized);\n                }\n                return 0;\n            }\n\n            double dist = _distance_circle_to_sphere(this, s, out p1, out p2, tolerance);\n\n            return dist;\n        }\n\n        private double _distance_circle_to_sphere(Circle3d c1, Sphere c2, out Point3d p1, out Point3d p2, double tol)\n        // Use quadratic interpolation to find closest point on circle\n        // p1 and p2 - closest points on circle and sphere respectively\n        {\n            double d1 = 1e20;\n            double t1 = 0;\n            Point3d p;\n\n            for (int i = 0; i < 16; i++)\n            {\n                double t = i * Math.PI / 8;\n                p = c1.ParametricForm(t);\n                double dist = p.DistanceTo(c2);\n                if (dist < d1)\n                {\n                    d1 = dist;\n                    t1 = t;\n                }\n            }\n            double t2 = t1 - Math.PI / 8;\n            p = c1.ParametricForm(t2);\n            double d2 = p.DistanceTo(c2);\n            double t3 = t1 + Math.PI / 8;\n            p = c1.ParametricForm(t3);\n            double d3 = p.DistanceTo(c2);\n\n            int iter = 0;\n            while (d2 - d1 > 0.2 * tol && d1 > tol)\n            {\n                if (++iter > 100) break;\n\n                double ax = 2.0 * d1 / (t1 - t2) / (t1 - t3);\n                double aa = 0.5 * ax * (t2 + t3);\n                double bx = 2.0 * d2 / (t2 - t1) / (t2 - t3);\n                double bb = 0.5 * bx * (t1 + t3);\n                double cx = 2.0 * d3 / (t3 - t1) / (t3 - t2);\n                double cc = 0.5 * cx * (t1 + t2);\n\n                double t = (aa + bb + cc) / (ax + bx + cx);\n                p = c1.ParametricForm(t);\n                double d = p.DistanceTo(c2);\n\n                if (d < d1)\n                {\n                    if (t > t2 & t < t1)\n                    {\n                        t3 = t1; d3 = d1;\n                    }\n                    else\n                    {\n                        t2 = t1; d2 = d1;\n                    }\n                    t1 = t; d1 = d;\n                }\n                else\n                {\n                    if (t < t1)\n                    {\n                        t2 = t; d2 = d;\n                    }\n                    else\n                    {\n                        t3 = t; d3 = d;\n                    }\n                }\n\n\n            }\n\n            p1 = c1.ParametricForm(t1);\n            p2 = c2.ClosestPoint(p1);\n            return d1;\n        }\n\n        /// <summary>\n        /// Shortest distance between line and circle (including interior points)\n        /// </summary>\n        public double DistanceTo(Line3d l)\n        {\n            Point3d point_on_circle, point_on_line;\n            double dist = _distance_circle_to_line(l, out point_on_circle, out point_on_line);\n            return dist;\n        }\n\n        /// <summary>\n        /// Shortest distance between line and circle (excluding interior points)\n        /// </summary>\n        public double DistanceToBoundary(Line3d l)\n        {\n            Point3d point_on_circle, point_on_line;\n            double dist = _distance_circle_boundary_to_line(l, out point_on_circle, out point_on_line);\n            return dist;\n        }\n\n        /// <summary>\n        /// Shortest distance between line and circle (including interior points)\n        /// </summary>\n        /// <param name=\"l\">Target line</param>\n        /// <param name=\"point_on_circle\">Closest point on circle</param>\n        /// <param name=\"point_on_line\">Closest point on line</param>\n        public double DistanceTo(Line3d l, out Point3d point_on_circle, out Point3d point_on_line)\n        {\n            double dist = _distance_circle_to_line(l, out point_on_circle, out point_on_line);\n            return dist;\n        }\n\n        /// <summary>\n        /// Shortest distance between line and circle (excluding interior points)\n        /// </summary>\n        /// <param name=\"l\">Target line</param>\n        /// <param name=\"point_on_circle\">Closest point on circle</param>\n        /// <param name=\"point_on_line\">Closest point on line</param>\n        public double DistanceToBoundary(Line3d l, out Point3d point_on_circle, out Point3d point_on_line)\n        {\n            double dist = _distance_circle_boundary_to_line(l, out point_on_circle, out point_on_line);\n            return dist;\n        }\n\n        /// <summary>\n        /// Shortest distance between ray and circle (including interior points)\n        /// </summary>\n        public double DistanceTo(Ray3d r)\n        {\n            Point3d point_on_circle, point_on_ray;\n            return DistanceTo(r, out point_on_circle, out point_on_ray);\n        }\n\n        /// <summary>\n        /// Shortest distance between ray and circle (including interior points)\n        /// </summary>\n        /// <param name=\"r\">Target ray</param>\n        /// <param name=\"point_on_circle\">Closest point on circle</param>\n        /// <param name=\"point_on_ray\">Closest point on ray</param>\n        public double DistanceTo(Ray3d r, out Point3d point_on_circle, out Point3d point_on_ray)\n        {\n            double dist = _distance_circle_to_line(r.ToLine, out point_on_circle, out point_on_ray);\n\n            if (point_on_ray.BelongsTo(r)) return dist;\n\n            point_on_ray = r.Point;\n            point_on_circle = this.ClosestPoint(point_on_ray);\n            return point_on_ray.DistanceTo(point_on_circle);\n        }\n\n        /// <summary>\n        /// Shortest distance between segment and circle (including interior points)\n        /// </summary>\n        public double DistanceTo(Segment3d s)\n        {\n            Point3d point_on_circle, point_on_ray;\n            return DistanceTo(s, out point_on_circle, out point_on_ray);\n        }\n\n        /// <summary>\n        /// Shortest distance between segment and circle (including interior points)\n        /// </summary>\n        /// <param name=\"s\">Target segment</param>\n        /// <param name=\"point_on_circle\">Closest point on circle</param>\n        /// <param name=\"point_on_segment\">Closest point on segment</param>\n        public double DistanceTo(Segment3d s, out Point3d point_on_circle, out Point3d point_on_segment)\n        {\n            Line3d l = s.Line;\n            Plane3d plane = this.ToPlane;\n            if (l.IsNotParallelTo(plane._normal))\n            {\n                Line3d l_projection = (Line3d)l.ProjectionTo(plane);\n                Object obj = l_projection.IntersectionWith(this);\n                if (obj != null && obj.GetType() == typeof(Segment3d))\n                {\n                    Segment3d segm = (Segment3d)obj;\n                    return s.DistanceTo(segm, out point_on_segment, out point_on_circle);\n                }\n                if (obj != null && obj.GetType() == typeof(Point3d))\n                {\n                    point_on_circle = (Point3d)obj;\n                    point_on_segment = s.ClosestPoint(point_on_circle);\n                    return point_on_segment.DistanceTo(point_on_circle);\n                }\n            }\n\n            // Line is parallel\n            if (l.IsParallelTo(this))\n            {\n                point_on_segment = this.Center.ProjectionTo(l);\n                if (s._AxialPointLocation(point_on_segment) >= 0)\n                {\n                    point_on_circle = this.ClosestPoint(point_on_segment);\n                    return point_on_circle.DistanceTo(point_on_segment);\n                }\n            }\n            \n            \n            double dist = _distance_circle_boundary_to_line(l, out point_on_circle, out point_on_segment);\n\n            int code = s._AxialPointLocation(point_on_segment);\n            if (code >= 0)\n            {\n                return dist;\n            }\n            else if (code == -1)\n            {\n                point_on_circle = this.ClosestPoint(s.P1);\n                point_on_segment = s.P1;\n            }\n            else\n            {\n                point_on_circle = this.ClosestPoint(s.P2);\n                point_on_segment = s.P2;\n            }\n\n            return point_on_circle.DistanceTo(point_on_segment);\n\n        }\n\n\n        /// <summary>\n        /// Shortest distance between line and circle (including interior points)\n        /// </summary>\n        /// <param name=\"l\">Target line</param>\n        /// <param name=\"p1\">Closest point on circle</param>\n        /// <param name=\"p2\">Closest point on line</param>\n        private double _distance_circle_to_line(Line3d l, out Point3d p1, out Point3d p2)\n        {\n\n            // Line is parallel\n            if (l.IsParallelTo(this))\n            {\n                p2 = this.Center.ProjectionTo(l);\n                p1 = this.ClosestPoint(p2);\n                return p1.DistanceTo(p2);\n            }\n\n            // Intrsecting line\n            object obj = l.IntersectionWith(this);\n            if (obj != null)\n            {\n                p1 = (Point3d)obj;\n                p2 = p1;\n                return 0;\n            }\n\n            return _distance_circle_boundary_to_line(l, out p1, out p2);\n        }\n\n        /// <summary>\n        /// Shortest distance between line and circle's boundary (excluding interior points)\n        /// (only one point will be returned for symmetrical case)\n        /// </summary>\n        /// <param name=\"l\">Target line</param>\n        /// <param name=\"point_on_circle\">Closest point on circle</param>\n        /// <param name=\"point_on_line\">Closest point on line</param>\n        private double _distance_circle_boundary_to_line(Line3d l, out Point3d point_on_circle, out Point3d point_on_line)\n        {\n\n            // Line is parallel\n            if (l.IsParallelTo(this))\n            {\n                Plane3d plane = this.ToPlane;\n                Line3d line_proj = (Line3d)l.ProjectionTo(plane);\n\n                object obj = line_proj.IntersectionWith(this);\n                if (obj == null)\n                {\n                    // Non-intersecting objects\n                    point_on_line = this.Center.ProjectionTo(l);\n                    point_on_circle = this.ClosestPoint(point_on_line);\n                    return point_on_line.DistanceTo(point_on_circle);\n                }\n                else if (obj.GetType() == typeof(Point3d))\n                {\n                    // Touching objects\n                    point_on_circle = (Point3d)obj;\n                    point_on_line = point_on_circle.ProjectionTo(l);\n                    return point_on_line.DistanceTo(point_on_circle);\n                }\n                else\n                {\n                    // Intrsecting objects, only one point will be used\n                    Segment3d segm = (Segment3d)obj;\n                    point_on_circle = segm.P1;\n                    point_on_line = point_on_circle.ProjectionTo(l);\n                    return point_on_line.DistanceTo(point_on_circle);\n                }\n            }\n\n            // Orthogonal line\n            if (l.IsOrthogonalTo(this))\n            {\n                Plane3d plane = this.ToPlane;\n                Point3d projection_point = (Point3d)l.IntersectionWith(plane);\n\n                if (projection_point == this.Center)\n                {\n                    point_on_line = projection_point;\n                    point_on_circle = this.ParametricForm(0);\n                    return point_on_line.DistanceTo(point_on_circle);\n                }\n                else\n                {\n                    Vector3d v = new Vector3d(this.Center, projection_point).Normalized;\n                    point_on_line = projection_point;\n                    point_on_circle = this.Center.Translate(this.R * v);\n                    return point_on_line.DistanceTo(point_on_circle);\n                }\n            }\n\n\n            // General case\n\n            double d1 = 1e20;\n            double t1 = 0;\n            Point3d p;\n\n            for (int i = 0; i < 16; i++)\n            {\n                double t = i * Math.PI / 8;\n                p = this.ParametricForm(t);\n                double dist = p.DistanceTo(l);\n                if (dist < d1)\n                {\n                    d1 = dist;\n                    t1 = t;\n                }\n            }\n            double t2 = t1 - Math.PI / 8;\n            p = this.ParametricForm(t2);\n            double d2 = p.DistanceTo(l);\n            double t3 = t1 + Math.PI / 8;\n            p = this.ParametricForm(t3);\n            double d3 = p.DistanceTo(l);\n\n            int iter = 0;\n            while (d2 - d1 > 0.2 * GeometRi3D.DefaultTolerance && d1 > GeometRi3D.DefaultTolerance)\n            {\n                if (++iter > 100) break;\n\n                double ax = 2.0 * d1 / (t1 - t2) / (t1 - t3);\n                double aa = 0.5 * ax * (t2 + t3);\n                double bx = 2.0 * d2 / (t2 - t1) / (t2 - t3);\n                double bb = 0.5 * bx * (t1 + t3);\n                double cx = 2.0 * d3 / (t3 - t1) / (t3 - t2);\n                double cc = 0.5 * cx * (t1 + t2);\n\n                double t = (aa + bb + cc) / (ax + bx + cx);\n                p = this.ParametricForm(t);\n                double d = p.DistanceTo(l);\n\n                if (d < d1)\n                {\n                    if (t > t2 & t < t1)\n                    {\n                        t3 = t1; d3 = d1;\n                    }\n                    else\n                    {\n                        t2 = t1; d2 = d1;\n                    }\n                    t1 = t; d1 = d;\n                }\n                else\n                {\n                    if (t < t1)\n                    {\n                        t2 = t; d2 = d;\n                    }\n                    else\n                    {\n                        t3 = t; d3 = d;\n                    }\n                }\n\n\n            }\n\n            point_on_circle = this.ParametricForm(t1);\n            point_on_line = point_on_circle.ProjectionTo(l);\n            return point_on_line.DistanceTo(point_on_circle);\n\n        }\n\n\n        /// <summary>\n        /// Shortest distance between triangle and circle (including interior points)\n        /// </summary>\n        public double DistanceTo(Triangle t)\n        {\n            Point3d point_on_circle, point_on_triangle;\n            return DistanceTo(t, out point_on_circle, out point_on_triangle);\n        }\n\n        /// <summary>\n        /// Shortest distance between triangle and circle (including interior points)\n        /// </summary>\n        /// <param name=\"t\">Target triangle</param>\n        /// <param name=\"point_on_circle\">Closest point on circle</param>\n        /// <param name=\"point_on_triangle\">Closest point on triangle</param>\n        public double DistanceTo(Triangle t, out Point3d point_on_circle, out Point3d point_on_triangle)\n        {\n            double dist = this.DistanceTo(t.Plane, out point_on_circle, out point_on_triangle);\n            if (t.DistanceTo(point_on_triangle) <= GeometRi3D.DefaultTolerance)\n            {\n                return dist;\n            }\n\n            Segment3d AB = new Segment3d(t.A, t.B);\n            Segment3d BC = new Segment3d(t.B, t.C);\n            Segment3d AC = new Segment3d(t.A, t.C);\n\n            dist = this.DistanceTo(AB, out point_on_circle, out point_on_triangle);\n            Point3d point_on_circle2, point_on_triangle2;\n            double dist2 = this.DistanceTo(BC, out point_on_circle2, out point_on_triangle2);\n            if (dist2 < dist)\n            {\n                dist = dist2;\n                point_on_circle = point_on_circle2;\n                point_on_triangle = point_on_triangle2;\n            }\n            dist2 = this.DistanceTo(AC, out point_on_circle2, out point_on_triangle2);\n            if (dist2 < dist)\n            {\n                dist = dist2;\n                point_on_circle = point_on_circle2;\n                point_on_triangle = point_on_triangle2;\n            }\n            return dist;\n        }\n\n        /// <summary>\n        /// Shortest distance from circle to box\n        /// </summary>\n        public double DistanceTo(Box3d box)\n        {\n            return box.DistanceTo(this);\n        }\n\n        /// <summary>\n        /// Shortest distance from circle to convex polyhedron\n        /// </summary>\n        public double DistanceTo(ConvexPolyhedron cp)\n        {\n            return cp.DistanceTo(this);\n        }\n        #endregion\n\n        /// <summary>\n        /// Intersection check between circle and sphere\n        /// </summary>\n        public bool Intersects(Sphere s)\n        {\n            if (this._point.DistanceTo(s.Center) <= this.R + s.R)\n            {\n                Object obj = s.IntersectionWith(this.ToPlane);\n                if (obj != null && obj.GetType() == typeof(Circle3d))\n                {\n                    // Check for circle-circle intersection\n                    if (this.IntersectionWith((Circle3d)obj) != null)\n                        return true;\n                }\n                else if (obj != null && obj.GetType() == typeof(Point3d))\n                {\n                    return ((Point3d)obj).BelongsTo(this);\n                }\n                else\n                {\n                    return false;\n                }\n            }\n            return false;\n        }\n\n        /// <summary>\n        /// Intersection check between two circles\n        /// </summary>\n        public bool Intersects(Circle3d c)\n        {\n\n            // Relative tolerance ================================\n            if (!GeometRi3D.UseAbsoluteTolerance)\n            {\n                double tol = GeometRi3D.Tolerance;\n                GeometRi3D.Tolerance = tol * Max(this.R, c.R);\n                GeometRi3D.UseAbsoluteTolerance = true;\n                bool result = this.Intersects(c);\n                GeometRi3D.UseAbsoluteTolerance = false;\n                GeometRi3D.Tolerance = tol;\n                return result;\n            }\n            //====================================================\n\n            // Early exit (separated circles)\n            double d = this._point.DistanceTo(c._point);\n            if (d > this.R + c.R + GeometRi3D.Tolerance)\n                return false;\n\n            //this._normal.IsParallelTo(c._normal)\n            if (GeometRi3D.AlmostEqual(Abs(this._normal * c._normal), 1.0))\n            {\n                if (this._point.BelongsTo(new Plane3d(c._point, c._normal)))\n                {\n                    // Coplanar objects\n                    if (d <= this.R + c.R + GeometRi3D.Tolerance)\n                    {\n                        return true;\n                    }\n                    else\n                    {\n                        return false;\n                    }  \n                }\n                else\n                {\n                    // parallel objects\n                    return false;\n                }\n            }\n            else\n            {\n                // Check 3D intersection\n                Vector3d v = new Vector3d(this._point, c._point);\n                double this_norm = this._normal.Norm;\n                double c_norm = c._normal.Norm;\n\n                double cos_angle1 = this._normal * v / this_norm / d;\n                double delta1 = Abs(d * cos_angle1);\n\n                double sin_angle2 = this._normal.Cross(c._normal).Norm / this_norm / c_norm;\n                double delta2 = Abs(c.R * sin_angle2);\n\n                if (delta1 > delta2) return false;\n\n                cos_angle1 = c._normal * v / c_norm / d;\n                delta1 = Abs(d * cos_angle1);\n                delta2 = Abs(this.R * sin_angle2);\n\n                if (delta1 > delta2) return false;\n\n\n\n                return _circle_circle_intersection_check_2(c);\n\n            }\n\n        }\n\n        private bool _circle_circle_intersection_check_2(Circle3d c)\n        {\n            Segment3d segm;\n            double dist;\n\n            Object obj = this.IntersectionWith(c.ToPlane);\n            if (obj == null) return false;\n            if (obj != null && obj.GetType() == typeof(Point3d))\n            {\n                Point3d point = (Point3d)obj;\n                dist = c.Center.DistanceTo(point);\n            }\n            else\n            {\n                segm = (Segment3d)obj;\n                dist = c.Center.DistanceTo(segm);\n            }\n\n            if (dist <= c.R + GeometRi3D.Tolerance)\n            {\n                return true;\n            }\n            else\n            {\n                return false;\n            }\n\n        }\n\n        private bool _circle_circle_intersection_check(Circle3d c)\n        {\n            Plane3d plane_this = new Plane3d(this._point, this._normal);\n\n            Line3d l = (Line3d)plane_this.IntersectionWith(new Plane3d(c._point, c._normal));\n            Coord3d local_coord = new Coord3d(this._point, l.Direction, this._normal.Cross(l.Direction));\n            Point3d p = l.Point.ConvertTo(local_coord);\n\n            if (GeometRi3D.Greater(Abs(p.Y), this.R))\n            {\n                // No intersection\n                return false;\n            }\n            else if (GeometRi3D.AlmostEqual(Abs(p.Y), this.R))\n            {\n                // Intersection in one point\n                Point3d pp = new Point3d(0, p.Y, 0, local_coord);\n                if (pp.DistanceTo(c._point) <= c.R + GeometRi3D.Tolerance)\n                {\n                    return true;\n                }\n                else\n                {\n                    return false;\n                }\n            }\n            else\n            {\n                double dd = Sqrt(this.R * this.R - p.Y * p.Y);\n                Point3d p1 = new Point3d(-dd, p.Y, 0, local_coord);\n                Point3d p2 = new Point3d(dd, p.Y, 0, local_coord);\n\n                // check if at least one point is outside circle \"c\"\n                if (p1.DistanceTo(c._point) <= c.R + GeometRi3D.Tolerance) return true;\n\n                // Now check if segment (p1,p2) intrsects circle \"c\"\n                // Use local coord with center in c.Point and X-axis aligned with segment\n                local_coord = new Coord3d(c._point, l.Direction, c._normal.Cross(l.Direction));\n                p1 = p1.ConvertTo(local_coord);\n                p2 = p2.ConvertTo(local_coord);\n\n                // use parametric form\n                // x=t*x1+(1-t)x2\n                // y=t*y1+(1-t)y2\n                // and take into account that y1=y2, x0=y0=0\n                double aa = (p1.X - p2.X) * (p1.X - p2.X);\n                double bb = 2 * p2.X * (p1.X - p2.X);\n                double cc = p2.X * p2.X + p2.Y * p2.Y - c.R * c.R;\n                double discr = bb * bb - 4 * aa * cc;\n\n                if (discr < 0)\n                {\n                    return false;\n                }\n                else\n                {\n                    discr = Sqrt(discr);\n                    double t1 = (-bb + discr) / (2 * aa);\n                    double t2 = (-bb - discr) / (2 * aa);\n                    if ((t1 >= 0 && t1 <= 1) || (t2 >= 0 && t2 <= 1))\n                    {\n                        return true;\n                    }\n                    else\n                    {\n                        return false;\n                    }\n                }\n            }\n        }\n\n\n\n        /// <summary>\n        /// Intersection check between circle and triangle\n        /// </summary>\n        public bool Intersects(Triangle t)\n        {\n            Plane3d t_plane = t.Plane;\n            if (this.DistanceTo(t_plane) > 0) return false;\n\n            if (this.IsCoplanarTo(t))\n            {\n                if (t.A.DistanceTo(this._point) <= this._r) return true;\n                if (t.B.DistanceTo(this._point) <= this._r) return true;\n                if (t.C.DistanceTo(this._point) <= this._r) return true;\n\n                if (this._point.BelongsTo(t)) return true;\n                if (this.IntersectionWith(new Segment3d(t.A, t.B)) != null) return true;\n                if (this.IntersectionWith(new Segment3d(t.B, t.C)) != null) return true;\n                if (this.IntersectionWith(new Segment3d(t.C, t.A)) != null) return true;\n            }\n            object obj = this.IntersectionWith(t_plane);\n            if (obj != null && obj.GetType() == typeof(Point3d))\n            {\n                return ((Point3d)obj).BelongsTo(t);\n            }\n            else if (obj != null && obj.GetType() == typeof(Segment3d))\n            {\n                return ((Segment3d)obj).IntersectionWith(t) != null;\n            }\n\n            return false;\n        }\n\n        /// <summary>\n        /// Intersection check between circle and box\n        /// </summary>\n        public bool Intersects(Box3d box)\n        {\n            return box.Intersects(this);\n        }\n\n        /// <summary>\n        /// Intersection check between circle and segment\n        /// </summary>\n        public bool Intersects(Segment3d s)\n        {\n            return this.IntersectionWith(s) != null;\n        }\n\n        /// <summary>\n        /// Orthogonal projection of the circle to plane\n        /// </summary>\n        public Ellipse ProjectionTo(Plane3d s)\n        {\n            return this.ToEllipse.ProjectionTo(s);\n        }\n\n        /// <summary>\n        /// Orthogonal projection of the circle to line\n        /// </summary>\n        public Segment3d ProjectionTo(Line3d l)\n        {\n            double s = _r * Cos(l.AngleTo(this));\n            Vector3d v = l.Direction.Normalized;\n            Point3d p = _point.ProjectionTo(l);\n            return new Segment3d(p.Translate(-s * v), p.Translate(s * v));\n        }\n\n        /// <summary>\n        /// Intersection of circle with line.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'.\n        /// </summary>\n        public object IntersectionWith(Line3d l)\n        {\n\n            // Relative tolerance ================================\n            if (!GeometRi3D.UseAbsoluteTolerance)\n            {\n                double tol = GeometRi3D.Tolerance;\n                GeometRi3D.Tolerance = tol * this.R;\n                GeometRi3D.UseAbsoluteTolerance = true;\n                object result = this.IntersectionWith(l);\n                GeometRi3D.UseAbsoluteTolerance = false;\n                GeometRi3D.Tolerance = tol;\n                return result;\n            }\n            //====================================================\n\n\n            if (l.Direction.IsOrthogonalTo(this._normal))\n            {\n                if (l.Point.BelongsTo(new Plane3d(this._point, this._normal)))\n                {\n                    // coplanar objects\n                    // Find intersection of line and circle (2D)\n\n                    // Local coord: X - line direction, Z - circle normal\n                    Coord3d local_coord = new Coord3d(this._point, l.Direction, this._normal.Cross(l.Direction));\n                    Point3d p = l.Point.ConvertTo(local_coord);\n\n                    double c = p.Y;\n\n                    if (Abs(c) > this.R + GeometRi3D.Tolerance)\n                    {\n                        return null;\n                    }\n                    else if (Abs(c) < this.R)\n                    {\n                        double x1 = Sqrt(this.R * this.R - Abs(c) * Abs(c));\n                        double x2 = -x1;\n                        return new Segment3d(new Point3d(x1, c, 0, local_coord), new Point3d(x2, c, 0, local_coord));\n                    }\n                    else if (c > 0)\n                    {\n                        return new Point3d(0, this.R, 0, local_coord);\n                    }\n                    else\n                    {\n                        return new Point3d(0, -this.R, 0, local_coord);\n                    }\n\n                }\n                else\n                {\n                    // parallel objects\n                    return null;\n                }\n            }\n            else\n            {\n                // Line intersects circle' plane\n                Point3d p = (Point3d)l.IntersectionWith(new Plane3d(this._point, this._normal));\n                if (p.DistanceTo(this._point) < this.R + GeometRi3D.Tolerance)\n                {\n                    return p;\n                }\n                else\n                {\n                    return null;\n                }\n            }\n        }\n\n        /// <summary>\n        /// Intersection of circle with segment.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'.\n        /// </summary>\n        public object IntersectionWith(Segment3d s)\n        {\n\n            // Relative tolerance ================================\n            if (!GeometRi3D.UseAbsoluteTolerance)\n            {\n                double tol = GeometRi3D.Tolerance;\n                GeometRi3D.Tolerance = tol * this.R;\n                GeometRi3D.UseAbsoluteTolerance = true;\n                object result = this.IntersectionWith(s);\n                GeometRi3D.UseAbsoluteTolerance = false;\n                GeometRi3D.Tolerance = tol;\n                return result;\n            }\n            //====================================================\n\n            object obj = this.IntersectionWith(s.Line);\n\n            if (obj == null)\n            {\n                return null;\n            }\n            else if (obj.GetType() == typeof(Point3d))\n            {\n                Point3d p = (Point3d)obj;\n                if (p.BelongsTo(s))\n                {\n                    return p;\n                }\n                else\n                {\n                    return null;\n                }\n            }\n            else\n            {\n                return s.IntersectionWith((Segment3d)obj);\n            }\n        }\n\n        /// <summary>\n        /// Intersection of circle with ray.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'.\n        /// </summary>\n        public object IntersectionWith(Ray3d r)\n        {\n\n            // Relative tolerance ================================\n            if (!GeometRi3D.UseAbsoluteTolerance)\n            {\n                double tol = GeometRi3D.Tolerance;\n                GeometRi3D.Tolerance = tol * this.R;\n                GeometRi3D.UseAbsoluteTolerance = true;\n                object result = this.IntersectionWith(r);\n                GeometRi3D.UseAbsoluteTolerance = false;\n                GeometRi3D.Tolerance = tol;\n                return result;\n            }\n            //====================================================\n\n            object obj = this.IntersectionWith(r.ToLine);\n\n            if (obj == null)\n            {\n                return null;\n            }\n            else if (obj.GetType() == typeof(Point3d))\n            {\n                Point3d p = (Point3d)obj;\n                if (p.BelongsTo(r))\n                {\n                    return p;\n                }\n                else\n                {\n                    return null;\n                }\n            }\n            else\n            {\n                return r.IntersectionWith((Segment3d)obj);\n            }\n        }\n\n        /// <summary>\n        /// Intersection of circle with plane.\n        /// Returns 'null' (no intersection) or object of type 'Circle3d', 'Point3d' or 'Segment3d'.\n        /// </summary>\n        public object IntersectionWith(Plane3d s)\n        {\n\n            // Relative tolerance ================================\n            if (!GeometRi3D.UseAbsoluteTolerance)\n            {\n                double tol = GeometRi3D.Tolerance;\n                GeometRi3D.Tolerance = tol * this.R;\n                GeometRi3D.UseAbsoluteTolerance = true;\n                object result = this.IntersectionWith(s);\n                GeometRi3D.UseAbsoluteTolerance = false;\n                GeometRi3D.Tolerance = tol;\n                return result;\n            }\n            //====================================================\n\n            if (this._normal.IsParallelTo(s.Normal))\n            {\n                if (this._point.BelongsTo(s))\n                {\n                    // coplanar objects\n                    return this.Copy();\n                }\n                else\n                {\n                    // parallel objects\n                    return null;\n                }\n            }\n            else\n            {\n\n                Vector3d v1 = this._normal.Cross(s.Normal);\n                Vector3d v2 = this._normal.Cross(v1);\n                Line3d l = new Line3d(this._point, v2);\n                Point3d intersection_point = (Point3d)l.IntersectionWith(s);\n\n                double dist = intersection_point.DistanceTo(this.Center);\n\n                if (Abs(R - dist) <= GeometRi3D.DefaultTolerance)\n                {\n                    // Point\n                    return intersection_point;\n                }\n                else if (R - dist > 0)\n                {\n                    // Segment\n                    double half_length = Sqrt(R * R - dist * dist);\n                    v1 = v1.Normalized;\n                    Point3d p1 = intersection_point.Translate(half_length * v1);\n                    Point3d p2 = intersection_point.Translate(-half_length * v1);\n                    return new Segment3d(p1, p2);\n                }\n                else\n                {\n                    return null;\n                }\n            }\n\n        }\n\n        /// <summary>\n        /// Intersection of two circles.\n        /// Returns 'null' (no intersection) or object of type 'Circle3d', 'Point3d' or 'Segment3d'.\n        /// In 2D (coplanar circles) the segment will define two intersection points.\n        /// </summary>\n        public object IntersectionWith(Circle3d c)\n        {\n\n            // Relative tolerance ================================\n            if (!GeometRi3D.UseAbsoluteTolerance)\n            {\n                double tol = GeometRi3D.Tolerance;\n                GeometRi3D.Tolerance = tol * Max(this.R, c.R);\n                GeometRi3D.UseAbsoluteTolerance = true;\n                object result = this.IntersectionWith(c);\n                GeometRi3D.UseAbsoluteTolerance = false;\n                GeometRi3D.Tolerance = tol;\n                return result;\n            }\n            //====================================================\n\n            // Early exit (separated circles)\n            double d = this._point.DistanceTo(c._point);\n            if (d > this.R  + c.R  +  GeometRi3D.Tolerance)\n                return null;\n\n            if (this._normal.IsParallelTo(c._normal))\n            {\n                if (this._point.BelongsTo(new Plane3d(c._point, c._normal)))\n                {\n                    // Coplanar objects\n                    // Search 2D intersection of two circles\n\n                    // Equal circles\n                    if (GeometRi3D.AlmostEqual(d, 0) && GeometRi3D.AlmostEqual(this.R, c.R))\n                    {\n                        return this.Copy();\n                    }\n\n                    \n\n                    // One circle inside the other\n                    if (d < Abs(this.R - c.R) - GeometRi3D.Tolerance)\n                    {\n                        if (this.R > c.R)\n                        {\n                            return c.Copy();\n                        }\n                        else\n                        {\n                            return this.Copy();\n                        }\n                    }\n\n                    // Outer tangency\n                    if (GeometRi3D.AlmostEqual(d, this.R + c.R))\n                    {\n                        Vector3d vec = new Vector3d(this._point, c._point);\n                        return this._point.Translate(this.R * vec.Normalized);\n                    }\n\n                    // Inner tangency\n                    if (Abs(Abs(this.R - c.R) - d) < GeometRi3D.Tolerance)\n                    {\n                        Vector3d vec = new Vector3d(this._point, c._point);\n                        if (this.R > c.R)\n                        {\n                            return this._point.Translate(this.R * vec.Normalized);\n                        }\n                        else\n                        {\n                            return this._point.Translate(-this.R * vec.Normalized);\n                        }\n                        \n                    }\n\n                    // intersecting circles\n                    // Create local CS with origin in circle's center\n                    Vector3d vec1 = new Vector3d(this._point, c._point);\n                    Vector3d vec2 = vec1.Cross(this._normal);\n                    Coord3d local_cs = new Coord3d(this._point, vec1, vec2);\n\n                    double x = 0.5 * (d * d - c.R * c.R + this.R * this.R) / d;\n                    double y = 0.5 * Sqrt((-d + c.R - this.R) * (-d - c.R + this.R) * (-d + c.R + this.R) * (d + c.R + this.R)) / d;\n                    Point3d p1 = new Point3d(x, y, 0, local_cs);\n                    Point3d p2 = new Point3d(x, -y, 0, local_cs);\n                    return new Segment3d(p1, p2);\n                }\n                else\n                {\n                    // parallel objects\n                    return null;\n                }\n            }\n            else\n            {\n                // Check 3D intersection\n\n                Vector3d v = new Vector3d(this._point, c._point);\n                double this_norm = this._normal.Norm;\n                double c_norm = c._normal.Norm;\n\n                double cos_angle1 = this._normal * v / this_norm / d;\n                double delta1 = Abs(d * cos_angle1);\n\n                double sin_angle2 = this._normal.Cross(c._normal).Norm / this_norm / c_norm;\n                double delta2 = Abs(c.R * sin_angle2);\n\n                if (delta1 > delta2) return null;\n\n                cos_angle1 = c._normal * v / c_norm / d;\n                delta1 = Abs(d * cos_angle1);\n                delta2 = Abs(this.R * sin_angle2);\n\n                if (delta1 > delta2) return null;\n\n\n                Plane3d plane_this = new Plane3d(this._point, this._normal);\n                object obj = c.IntersectionWith(plane_this);\n\n                if (obj == null)\n                {\n                    return null;\n                }\n                else if (obj.GetType() == typeof(Point3d))\n                {\n                    Point3d p = (Point3d)obj;\n                    if (p.DistanceTo(this._point) < this.R + GeometRi3D.Tolerance)\n                    {\n                        return p;\n                    }\n                    else\n                    {\n                        return null;\n                    }\n                }\n                else\n                {\n                    Segment3d s = (Segment3d)obj;\n                    return s.IntersectionWith(this);\n                }\n\n            }\n\n        }\n\n        internal override int _PointLocation(Point3d p)\n        {\n            if (GeometRi3D.UseAbsoluteTolerance)\n            {\n                Plane3d s = new Plane3d(this.Center, this.Normal);\n                Point3d proj = p.ProjectionTo(s);\n                if (GeometRi3D.AlmostEqual(p.DistanceTo(proj), 0))\n                {\n                    if ( GeometRi3D.Smaller(p.DistanceTo(this.Center), this.R))\n                    {\n                        return 1; // Point is strictly inside\n                    }\n                    else if (GeometRi3D.AlmostEqual(p.DistanceTo(this.Center), this.R) )\n                    {\n                        return 0; // Point is on boundary\n                    }\n                    else\n                    {\n                        return -1; // Point is outside\n                    }\n                }\n                else\n                {\n                    return -1; // Point is outside\n                }\n            }\n            else\n            {\n                double tol = GeometRi3D.Tolerance;\n                GeometRi3D.Tolerance = tol * this.R;\n                GeometRi3D.UseAbsoluteTolerance = true;\n                int result = this._PointLocation(p);\n                GeometRi3D.UseAbsoluteTolerance = false;\n                GeometRi3D.Tolerance = tol;\n                return result;\n            }\n        }\n\n        #region \"AngleTo\"\n        /// <summary>\n        /// Angle between two objects in radians (0 &lt; angle &lt; Pi)\n        /// </summary>\n        public double AngleTo(ILinearObject obj)\n        {\n            return GeometRi3D.GetAngle(this, obj);\n        }\n        /// <summary>\n        /// Angle between two objects in degrees (0 &lt; angle &lt; 180)\n        /// </summary>\n        public double AngleToDeg(ILinearObject obj)\n        {\n            return AngleTo(obj) * 180 / PI;\n        }\n\n        /// <summary>\n        /// Angle between two objects in radians (0 &lt; angle &lt; Pi)\n        /// </summary>\n        public double AngleTo(IPlanarObject obj)\n        {\n            return GeometRi3D.GetAngle(this, obj);\n        }\n        /// <summary>\n        /// Angle between two objects in degrees (0 &lt; angle &lt; 180)\n        /// </summary>\n        public double AngleToDeg(IPlanarObject obj)\n        {\n            return AngleTo(obj) * 180 / PI;\n        }\n        #endregion\n\n        #region \"TranslateRotateReflect\"\n        /// <summary>\n        /// Translate circle by a vector\n        /// </summary>\n        public Circle3d Translate(Vector3d v)\n        {\n            return new Circle3d(this.Center.Translate(v), this.R, this.Normal);\n        }\n\n        /// <summary>\n        /// Rotate circle by a given rotation matrix\n        /// </summary>\n        [System.Obsolete(\"use Rotation object and specify rotation center: this.Rotate(Rotation r, Point3d p)\")]\n        public Circle3d Rotate(Matrix3d m)\n        {\n            return new Circle3d(this.Center.Rotate(m), this.R, this.Normal.Rotate(m));\n        }\n\n        /// <summary>\n        /// Rotate circle by a given rotation matrix around point 'p' as a rotation center\n        /// </summary>\n        [System.Obsolete(\"use Rotation object: this.Rotate(Rotation r, Point3d p)\")]\n        public Circle3d Rotate(Matrix3d m, Point3d p)\n        {\n            return new Circle3d(this.Center.Rotate(m, p), this.R, this.Normal.Rotate(m));\n        }\n\n        /// <summary>\n        /// Rotate circle around point 'p' as a rotation center\n        /// </summary>\n        public Circle3d Rotate(Rotation r, Point3d p)\n        {\n            return new Circle3d(this.Center.Rotate(r, p), this.R, this.Normal.Rotate(r));\n        }\n\n        /// <summary>\n        /// Reflect circle in given point\n        /// </summary>\n        public Circle3d ReflectIn(Point3d p)\n        {\n            return new Circle3d(this.Center.ReflectIn(p), this.R, this.Normal.ReflectIn(p));\n        }\n\n        /// <summary>\n        /// Reflect circle in given line\n        /// </summary>\n        public Circle3d ReflectIn(Line3d l)\n        {\n            return new Circle3d(this.Center.ReflectIn(l), this.R, this.Normal.ReflectIn(l));\n        }\n\n        /// <summary>\n        /// Reflect circle in given plane\n        /// </summary>\n        public Circle3d ReflectIn(Plane3d s)\n        {\n            return new Circle3d(this.Center.ReflectIn(s), this.R, this.Normal.ReflectIn(s));\n        }\n\n        /// <summary>\n        /// Scale circle relative to given point\n        /// </summary>\n        public virtual Circle3d Scale(double scale, Point3d scaling_center)\n        {\n            Point3d new_center = scaling_center + scale * (this.Center - scaling_center);\n            return new Circle3d(new_center, this._r * scale, this._normal);\n        }\n        #endregion\n\n        /// <summary>\n        /// Determines whether two objects are equal.\n        /// </summary>\n        public override bool Equals(object obj)\n        {\n            if (obj == null || (!object.ReferenceEquals(this.GetType(), obj.GetType())))\n            {\n                return false;\n            }\n            Circle3d c = (Circle3d)obj;\n\n            if (GeometRi3D.UseAbsoluteTolerance)\n            {\n                return c.Center == this.Center && Abs(c.R - this.R) <= GeometRi3D.Tolerance && c.Normal.IsParallelTo(this.Normal);\n            }\n            else\n            {\n                return Abs(c.Center.DistanceTo(this.Center)) / this.R <= GeometRi3D.Tolerance && \n                       Abs(c.R - this.R) / this.R  <= GeometRi3D.Tolerance && \n                       c.Normal.IsParallelTo(this.Normal);\n            }\n        }\n\n        /// <summary>\n        /// Returns the hashcode for the object.\n        /// </summary>\n        public override int GetHashCode()\n        {\n            return GeometRi3D.HashFunction(_point.GetHashCode(), _r.GetHashCode(), _normal.GetHashCode());\n        }\n\n        /// <summary>\n        /// String representation of an object in global coordinate system.\n        /// </summary>\n        public override String ToString()\n        {\n            return ToString(Coord3d.GlobalCS, false);\n        }\n\n        /// <summary>\n        /// String representation of an object in global coordinate system.\n        /// </summary>\n        public String ToString(bool full_precision = false)\n        {\n            return ToString(Coord3d.GlobalCS, full_precision);\n        }\n\n        /// <summary>\n        /// String representation of an object in reference coordinate system.\n        /// </summary>\n        public String ToString(Coord3d coord, bool full_precision = false)\n        {\n            string nl = System.Environment.NewLine;\n\n            if (coord == null) { coord = Coord3d.GlobalCS; }\n            Point3d P = _point.ConvertTo(coord);\n            Vector3d normal = _normal.ConvertTo(coord);\n\n            string str = string.Format(\"Circle: \") + nl;\n            if (full_precision)\n            {\n                str += string.Format(\"  Center -> ({0}, {1}, {2})\", P.X, P.Y, P.Z) + nl;\n                str += string.Format(\"  Radius -> {0}\", _r) + nl;\n                str += string.Format(\"  Normal -> ({0}, {1}, {2})\", normal.X, normal.Y, normal.Z);\n            }\n            else\n            {\n                str += string.Format(\"  Center -> ({0,10:g5}, {1,10:g5}, {2,10:g5})\", P.X, P.Y, P.Z) + nl;\n                str += string.Format(\"  Radius -> {0,10:g5}\", _r) + nl;\n                str += string.Format(\"  Normal -> ({0,10:g5}, {1,10:g5}, {2,10:g5})\", normal.X, normal.Y, normal.Z);\n            }\n\n            return str;\n        }\n\n        public String ToString(Coord3d coord, bool full_precision = false, bool code = true)\n        {\n            string nl = System.Environment.NewLine;\n\n            if (coord == null) { coord = Coord3d.GlobalCS; }\n            Point3d P = _point.ConvertTo(coord);\n            Vector3d normal = _normal.ConvertTo(coord);\n\n            string str = string.Format(\"Circle3d circle = new Circle3d(new Point3d({0}, {1}, {2}), {3}, new Vector3d({4}, {5}, {6}));\",\n                   P.X, P.Y, P.Z, this.R, normal.X, normal.Y, normal.Z) + nl;\n\n            return str;\n        }\n\n        // Operators overloads\n        //-----------------------------------------------------------------\n\n        public static bool operator ==(Circle3d c1, Circle3d c2)\n        {\n            if (object.ReferenceEquals(c1, null))\n                return object.ReferenceEquals(c2, null);\n            return c1.Equals(c2);\n        }\n        public static bool operator !=(Circle3d c1, Circle3d c2)\n        {\n            if (object.ReferenceEquals(c1, null))\n                return !object.ReferenceEquals(c2, null);\n            return !c1.Equals(c2);\n        }\n\n    }\n}\n\n\n"
  },
  {
    "path": "GeometRi/ConvexPolyhedron.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Runtime.CompilerServices;\nusing System.Text;\n\nnamespace GeometRi\n{\n    /// <summary>\n    /// Convex polyhedron with counterclockwise oriented faces (seen from outside).\n    /// </summary>\n#if NET20_OR_GREATER\n    [Serializable]\n#endif\n    public class ConvexPolyhedron : FiniteObject, IFiniteObject\n    {\n        public int numVertices, numEdges, numFaces;\n        public Point3d[] vertex;\n        public Edge[] edge;\n        public Face[] face;\n\n        private AABB _aabb = null;\n        private List<Segment3d> _list_e = null;\n\n        /// <summary>\n        /// Edge of a convex polyhedron.\n        /// </summary>\n#if NET20_OR_GREATER\n    [Serializable]\n#endif\n        public struct Edge\n        {\n            public int p1, p2;\n            internal ConvexPolyhedron parent;\n            public Edge(int P1, int P2)\n            {\n                p1 = P1;\n                p2 = P2;\n                parent = null;\n            }\n\n            public Point3d P1\n            {\n                get\n                {\n                    return parent.vertex[p1];\n                }\n            }\n\n            public Point3d P2\n            {\n                get\n                {\n                    return parent.vertex[p2];\n                }\n            }\n        }\n        public interface IVertex\n        {\n            Point3d this[int index] { get; }\n        }\n\n#if NET20_OR_GREATER\n    [Serializable]\n#endif\n        public struct Face : IVertex\n        {\n            public int numVertices;\n            public int[] vertex;\n            public Vector3d normal;\n            internal ConvexPolyhedron parent;\n            public Face(int numVertices, int[] vertex)\n            {\n                this.numVertices = numVertices;\n                this.vertex = vertex;\n                parent = null;\n                normal = null;\n            }\n\n            public double Area\n            {\n                get\n                {\n                    Vector3d v1, v2;\n                    v1 = new Vector3d(parent.vertex[vertex[0]], parent.vertex[vertex[1]]);\n                    double area = 0;\n                    for (int i = 0; i < vertex.Length - 2; i++)\n                    {\n                        v2 = new Vector3d(parent.vertex[vertex[0]], parent.vertex[vertex[i + 2]]);\n                        area += v1.Cross(v2).Norm;\n                        v1 = v2;\n                    }\n                    return area / 2;\n                }\n            }\n\n            public Point3d Center\n            {\n                get\n                {\n                    Point3d center = new Point3d(); ;\n                    foreach (int v in vertex)\n                    {\n                        center += parent.vertex[v];\n                    }\n                    return center / vertex.Length;\n                }\n            }\n\n            /// <summary>\n            /// Create prism by extruding face of convex polyhedron in the direction of face normal\n            /// </summary>\n            public ConvexPolyhedron Extrude(double distance, bool symmetrical = false)\n            {\n                return Extrude(normal, distance, symmetrical);\n            }\n\n            /// <summary>\n            /// Create prism by extruding face of convex polyhedron\n            /// </summary>\n            public ConvexPolyhedron Extrude(Vector3d direction, double distance, bool symmetrical = false)\n            {\n                Point3d[] new_vertices = new Point3d[numVertices * 2];\n                Edge[] edges = new Edge[numVertices * 3];\n                Face[] faces = new Face[numVertices + 2];\n                Vector3d traslation_vec = direction.Normalized * distance;\n                \n                for (int i = 0; i < numVertices; i++)\n                {\n                    new_vertices[i] = parent.vertex[vertex[i]].Copy();\n                    new_vertices[i + numVertices] = parent.vertex[vertex[i]].Translate(traslation_vec);\n                }\n\n                faces[0] = new Face(numVertices, new int[numVertices]);\n                faces[1] = new Face(numVertices, new int[numVertices]);\n\n                for (int i = 0; i < numVertices; i++)\n                {\n                    faces[0].vertex[i] = i;\n                    faces[1].vertex[i] = i + numVertices;\n                    if (i < numVertices - 1)\n                    {\n                        // regilar side face\n                        faces[i + 2] = new Face(4, new int[] { i, i + 1, i + 1 + numVertices, i + numVertices });\n                        edges[i] = new Edge(i, i + 1);\n                        edges[i + numVertices] = new Edge(i + numVertices, i + 1 + numVertices);\n                        edges[i + numVertices * 2] = new Edge(i, i + numVertices);\n                    }\n                    else\n                    {\n                        // last side face\n                        faces[i + 2] = new Face(4, new int[] { i, 0, numVertices, i + numVertices });\n                        edges[i] = new Edge(i, 0);\n                        edges[i + numVertices] = new Edge(i + numVertices, numVertices);\n                        edges[i + numVertices * 2] = new Edge(i, i + numVertices);\n                    }\n                }\n\n                ConvexPolyhedron cp = new ConvexPolyhedron(numVertices * 2, numVertices * 3, numVertices + 2, new_vertices, edges, faces);\n                cp.CheckFaceOrientation();\n\n                if (symmetrical)\n                {\n                    cp = cp.Translate(-traslation_vec / 2);\n                }\n\n                return cp;\n            }\n\n            Point3d IVertex.this[int index]\n            {\n                get\n                {\n                    return parent.vertex[vertex[index]];\n                }\n            }\n            /// <summary>\n            /// Returns a Point3d object for vertex [i]\n            /// </summary>\n            public IVertex Vertex\n            {\n                get\n                {\n                    return this;\n                }\n            }\n\n            internal void UpdateNormal()\n            {\n                normal = new Vector3d(parent.vertex[vertex[0]], parent.vertex[vertex[1]]).Cross(new Vector3d(parent.vertex[vertex[0]], parent.vertex[vertex[2]])).Normalized;\n            }\n        }\n\n\n\n        #region \"Constructors\"\n\n        /// <summary>\n        /// Creates general convex polyhedron from a lists of vertices, edges, and faces\n        /// </summary>\n        /// <param name=\"numVertices\">Number of vertices</param>\n        /// <param name=\"numEdges\">Number of edges</param>\n        /// <param name=\"numFaces\">Number of faces</param>\n        /// <param name=\"vertices\">List of vertices</param>\n        /// <param name=\"edges\">List of edges</param>\n        /// <param name=\"faces\">List of faces</param>\n        /// <param name=\"check_face_orientation\">Check and invert incorrectly oriented faces</param>\n        public ConvexPolyhedron(int numVertices, int numEdges, int numFaces, Point3d[] vertices, Edge[] edges, Face[] faces, bool check_face_orientation = false)\n        {\n            this.numVertices = numVertices;\n            this.numEdges = numEdges;\n            this.numFaces = numFaces;\n            this.vertex = vertices;\n            this.edge = edges;\n            this.face = faces;\n\n            // Initialize fields\n            for (int i = 0; i < edges.Length; i++)\n            {\n                edges[i].parent = this;\n            }\n            for (int i = 0; i < faces.Length; i++)\n            {\n                faces[i].parent = this;\n                faces[i].UpdateNormal();\n            }\n\n            if (check_face_orientation)\n            {\n                CheckFaceOrientation();\n            }\n\n        }\n\n        /// <summary>\n        /// Create ConvexPolyhedron object from a Tetrahedron object\n        /// </summary>\n        public static ConvexPolyhedron FromTetrahedron(Tetrahedron t)\n        {\n            Point3d[] vertices = new Point3d[4];\n            vertices[0] = t.A.Copy();\n            vertices[1] = t.B.Copy();\n            vertices[2] = t.C.Copy();\n            vertices[3] = t.D.Copy();\n\n            Edge[] edges = new Edge[6];\n            edges[0] = new Edge(0, 1);\n            edges[1] = new Edge(1, 2);\n            edges[2] = new Edge(2, 0);\n            edges[3] = new Edge(0, 3);\n            edges[4] = new Edge(1, 3);\n            edges[5] = new Edge(2, 3);\n\n            Face[] faces = new Face[4];\n            faces[0] = new Face(3, new int[] { 0, 1, 2 });\n            faces[1] = new Face(3, new int[] { 0, 1, 3 });\n            faces[2] = new Face(3, new int[] { 1, 2, 3 });\n            faces[3] = new Face(3, new int[] { 2, 0, 3 });\n\n            ConvexPolyhedron cp = new ConvexPolyhedron(4, 6, 4, vertices, edges, faces);\n            cp.CheckFaceOrientation();\n\n            return cp;\n        }\n\n        public static ConvexPolyhedron Cube(Point3d p_min, Point3d p_max)\n        {\n            return FromBox(new Box3d(p_min, p_max));\n        }\n\n        /// <summary>\n        /// Create ConvexPolyhedron object from a Box3d object\n        /// </summary>\n        public static ConvexPolyhedron FromBox(Box3d box)\n        {\n            Point3d[] vertices = new Point3d[8];\n            vertices[0] = box.P1.Copy();\n            vertices[1] = box.P2.Copy();\n            vertices[2] = box.P3.Copy();\n            vertices[3] = box.P4.Copy();\n            vertices[4] = box.P5.Copy();\n            vertices[5] = box.P6.Copy();\n            vertices[6] = box.P7.Copy();\n            vertices[7] = box.P8.Copy();\n\n            Edge[] edges = new Edge[12];\n            edges[0] = new Edge(0, 1);\n            edges[1] = new Edge(1, 2);\n            edges[2] = new Edge(2, 3);\n            edges[3] = new Edge(3, 0);\n            \n            edges[4] = new Edge(4, 5);\n            edges[5] = new Edge(5, 6);\n            edges[6] = new Edge(6, 7);\n            edges[7] = new Edge(7, 4);\n            \n            edges[8] = new Edge(0, 4);\n            edges[9] = new Edge(1, 5);\n            edges[10] = new Edge(2, 6);\n            edges[11] = new Edge(3, 7);\n\n            Face[] faces = new Face[6];\n            faces[0] = new Face(4, new int[] { 0, 3, 2, 1 });\n            faces[1] = new Face(4, new int[] { 4, 5, 6, 7 });\n            faces[2] = new Face(4, new int[] { 0, 1, 5, 4 });\n            faces[3] = new Face(4, new int[] { 2, 3, 7, 6 });\n            faces[4] = new Face(4, new int[] { 1, 2, 6, 5 });\n            faces[5] = new Face(4, new int[] { 0, 4, 7, 3 });\n\n            return new ConvexPolyhedron(8, 12, 6, vertices, edges, faces);\n        }\n\n        /// <summary>\n        /// Creates regular octahedron centered at origin with vertices:\n        /// <para>(±1,  0,  0)</para>\n        /// <para>( 0, ±1,  0)</para>\n        /// <para>( 0,  0, ±1)</para>\n        /// </summary>\n        public static ConvexPolyhedron Octahedron()\n        {\n            Point3d[] vertices = new Point3d[6];\n            vertices[0] = new Point3d(1, 0, 0);\n            vertices[1] = new Point3d(-1, 0, 0);\n            vertices[2] = new Point3d(0, 1, 0);\n            vertices[3] = new Point3d(0, -1, 0);\n            vertices[4] = new Point3d(0, 0, 1);\n            vertices[5] = new Point3d(0, 0, -1);\n\n            Edge[] edges = new Edge[12];\n            edges[0] = new Edge(0, 2);\n            edges[1] = new Edge(2, 1);\n            edges[2] = new Edge(1, 3);\n            edges[3] = new Edge(3, 0);\n\n            edges[4] = new Edge(0, 4);\n            edges[5] = new Edge(2, 4);\n            edges[6] = new Edge(1, 4);\n            edges[7] = new Edge(3, 4);\n\n            edges[8] = new Edge(0, 5);\n            edges[9] = new Edge(2, 5);\n            edges[10] = new Edge(1, 5);\n            edges[11] = new Edge(3, 5);\n\n            Face[] faces = new Face[8];\n            faces[0] = new Face(3, new int[] { 0, 2, 4 });\n            faces[1] = new Face(3, new int[] { 2, 1, 4 });\n            faces[2] = new Face(3, new int[] { 1, 3, 4 });\n            faces[3] = new Face(3, new int[] { 3, 0, 4 });\n            faces[4] = new Face(3, new int[] { 0, 3, 5 });\n            faces[5] = new Face(3, new int[] { 3, 1, 5 });\n            faces[6] = new Face(3, new int[] { 1, 2, 5 });\n            faces[7] = new Face(3, new int[] { 2, 0, 5 });\n\n            return new ConvexPolyhedron(6, 12, 8, vertices, edges, faces);\n        }\n\n\n        /// <summary>\n        /// Creates regular icosahedron centered at origin with vertices:\n        /// <para>( 0, ±f, ±1)</para>\n        /// <para>(±f, ±1,  0)</para>\n        /// <para>(±1,  0, ±f)</para>\n        /// <para>with 'f' equal to golden ratio (1+Sqrt(5))/2</para>\n        /// </summary>\n        public static ConvexPolyhedron Icosahedron()\n        {\n            double f = (1 + Math.Sqrt(5)) / 2;\n\n            Point3d[] vertices = new Point3d[12];\n            vertices[0] = new Point3d(0, f, 1);\n            vertices[1] = new Point3d(0, f, -1);\n            vertices[2] = new Point3d(0, -f, 1);\n            vertices[3] = new Point3d(0, -f, -1);\n\n            vertices[4] = new Point3d(f, 1, 0);\n            vertices[5] = new Point3d(f, -1, 0);\n            vertices[6] = new Point3d(-f, 1, 0);\n            vertices[7] = new Point3d(-f, -1, 0);\n\n            vertices[8] = new Point3d(1, 0, f);\n            vertices[9] = new Point3d(-1, 0, f);\n            vertices[10] = new Point3d(1, 0, -f);\n            vertices[11] = new Point3d(-1, 0, -f);\n\n            Edge[] edges = new Edge[30];\n            edges[0] = new Edge(0, 1);\n            edges[1] = new Edge(0, 4);\n            edges[2] = new Edge(0, 6);\n            edges[3] = new Edge(0, 8);\n            edges[4] = new Edge(0, 9);\n\n            edges[5] = new Edge(1, 4);\n            edges[6] = new Edge(1, 6);\n            edges[7] = new Edge(1, 10);\n            edges[8] = new Edge(1, 11);\n\n            edges[9] = new Edge(2, 3);\n            edges[10] = new Edge(2, 5);\n            edges[11] = new Edge(2, 7);\n            edges[12] = new Edge(2, 8);\n            edges[13] = new Edge(2, 9);\n\n            edges[14] = new Edge(3, 5);\n            edges[15] = new Edge(3, 7);\n            edges[16] = new Edge(3, 10);\n            edges[17] = new Edge(3, 11);\n\n            edges[18] = new Edge(4, 5);\n            edges[19] = new Edge(4, 8);\n            edges[20] = new Edge(4, 10);\n\n            edges[21] = new Edge(5, 8);\n            edges[22] = new Edge(5, 10);\n\n            edges[23] = new Edge(6, 7);\n            edges[24] = new Edge(6, 9);\n            edges[25] = new Edge(6, 11);\n\n            edges[26] = new Edge(7, 9);\n            edges[27] = new Edge(7, 11);\n\n            edges[28] = new Edge(8, 9);\n            edges[29] = new Edge(10, 11);\n\n            Face[] faces = new Face[20];\n            faces[0] = new Face(3, new int[] { 0, 4, 1 });\n            faces[1] = new Face(3, new int[] { 0, 1, 6 });\n            faces[2] = new Face(3, new int[] { 0, 6, 9 });\n            faces[3] = new Face(3, new int[] { 0, 9, 8 });\n            faces[4] = new Face(3, new int[] { 0, 8, 4 });\n\n            faces[5] = new Face(3, new int[] { 1, 4, 10 });\n            faces[6] = new Face(3, new int[] { 1, 10, 11 });\n            faces[7] = new Face(3, new int[] { 1, 11, 6 });\n\n            faces[8] = new Face(3, new int[] { 2, 3, 5 });\n            faces[9] = new Face(3, new int[] { 2, 5, 8 });\n            faces[10] = new Face(3, new int[] { 2, 8, 9 });\n            faces[11] = new Face(3, new int[] { 2, 9, 7 });\n            faces[12] = new Face(3, new int[] { 2, 7, 3 });\n\n            faces[13] = new Face(3, new int[] { 3, 10, 5 });\n            faces[14] = new Face(3, new int[] { 3, 7, 11 });\n            faces[15] = new Face(3, new int[] { 3, 11, 10 });\n\n            faces[16] = new Face(3, new int[] { 4, 8, 5 });\n            faces[17] = new Face(3, new int[] { 4, 5, 10 });\n            faces[18] = new Face(3, new int[] { 6, 7, 9 });\n            faces[19] = new Face(3, new int[] { 6, 11, 7 });\n\n            return new ConvexPolyhedron(12, 30, 20, vertices, edges, faces);\n        }\n\n        /// <summary>\n        /// Creates regular dodecahedron centered at origin with vertices:\n        /// <para>(±1, ±1, ±1)</para>\n        /// <para>( 0, ±φ, ±1/φ)</para>\n        /// <para>(±φ, ±1/φ,  0)</para> \n        /// <para>(±1/φ,  0, ±φ)</para>\n        /// <para>with 'φ' equal to golden ratio (1+Sqrt(5))/2</para>\n        /// </summary>\n        public static ConvexPolyhedron Dodecahedron()\n        {\n            double f = (1 + Math.Sqrt(5)) / 2;\n\n            Point3d[] vertices = new Point3d[20];\n            vertices[0] = new Point3d(-1, 1, 1);\n            vertices[1] = new Point3d(-1, -1, 1);\n            vertices[2] = new Point3d(1, -1, 1);\n            vertices[3] = new Point3d(1, 1, 1);\n            vertices[4] = new Point3d(-1, 1, -1);\n            vertices[5] = new Point3d(-1, -1, -1);\n            vertices[6] = new Point3d(1, -1, -1);\n            vertices[7] = new Point3d(1, 1, -1);\n\n            vertices[8] = new Point3d(0, f, 1 / f);\n            vertices[9] = new Point3d(0, -f, 1 / f);\n            vertices[10] = new Point3d(0, f, -1 / f);\n            vertices[11] = new Point3d(0, -f, -1 / f);\n\n            vertices[12] = new Point3d(f, 1 / f, 0);\n            vertices[13] = new Point3d(f, -1 / f, 0);\n            vertices[14] = new Point3d(-f, 1 / f, 0);\n            vertices[15] = new Point3d(-f, -1 / f, 0);\n\n            vertices[16] = new Point3d(1 / f, 0, f);\n            vertices[17] = new Point3d(-1 / f, 0, f);\n            vertices[18] = new Point3d(1 / f, 0, -f);\n            vertices[19] = new Point3d(-1 / f, 0, -f);\n\n            Edge[] edges = new Edge[30];\n            edges[0] = new Edge(0, 8);\n            edges[1] = new Edge(0, 14);\n            edges[2] = new Edge(0, 17);\n            edges[3] = new Edge(1, 9);\n            edges[4] = new Edge(1, 15);\n            edges[5] = new Edge(1, 17);\n            edges[6] = new Edge(2, 9);\n            edges[7] = new Edge(2, 13);\n            edges[8] = new Edge(2, 16);\n            edges[9] = new Edge(3, 8);\n            edges[10] = new Edge(3, 12);\n            edges[11] = new Edge(3, 16);\n\n            edges[12] = new Edge(4, 10);\n            edges[13] = new Edge(4, 14);\n            edges[14] = new Edge(4, 19);\n            edges[15] = new Edge(5, 11);\n            edges[16] = new Edge(5, 15);\n            edges[17] = new Edge(5, 19);\n            edges[18] = new Edge(6, 11);\n            edges[19] = new Edge(6, 13);\n            edges[20] = new Edge(6, 18);\n            edges[21] = new Edge(7, 10);\n            edges[22] = new Edge(7, 12);\n            edges[23] = new Edge(7, 18);\n\n            edges[24] = new Edge(8, 10);\n            edges[25] = new Edge(9, 11);\n            edges[26] = new Edge(12, 13);\n            edges[27] = new Edge(14, 15);\n            edges[28] = new Edge(16, 17);\n            edges[29] = new Edge(18, 19);\n\n            Face[] faces = new Face[12];\n            faces[0] = new Face(5, new int[] { 0, 14, 15, 1, 17 });\n            faces[1] = new Face(5, new int[] { 1, 15, 5, 11, 9 });\n            faces[2] = new Face(5, new int[] { 1, 9, 2, 16, 17 });\n            faces[3] = new Face(5, new int[] { 2, 9, 11, 6, 13 });\n\n            faces[4] = new Face(5, new int[] { 0, 17, 16, 3, 8 });\n            faces[5] = new Face(5, new int[] { 2, 13, 12, 3, 16 });\n            faces[6] = new Face(5, new int[] { 0, 8, 10, 4, 14 });\n            faces[7] = new Face(5, new int[] { 3, 12, 7, 10, 8 });\n            faces[8] = new Face(5, new int[] { 4, 10, 7, 18, 19 });\n            faces[9] = new Face(5, new int[] { 4, 19, 5, 15, 14 });\n            faces[10] = new Face(5, new int[] { 6, 18, 7, 12, 13 });\n            faces[11] = new Face(5, new int[] { 5, 19, 18, 6, 11 });\n\n\n            return new ConvexPolyhedron(20, 30, 12, vertices, edges, faces);\n        }\n\n        /// <summary>\n        /// Creates Rhombic dodecahedron\n        /// </summary>\n        public static ConvexPolyhedron RhombicDodecahedron()\n        {\n            Point3d[] vertices = new Point3d[14];\n            vertices[0] = new Point3d(-1, -1, -1);\n            vertices[1] = new Point3d(1, -1, -1);\n            vertices[2] = new Point3d(1, 1, -1);\n            vertices[3] = new Point3d(-1, 1, -1);\n            vertices[4] = new Point3d(-1, -1, 1);\n            vertices[5] = new Point3d(1, -1, 1);\n            vertices[6] = new Point3d(1, 1, 1);\n            vertices[7] = new Point3d(-1, 1, 1);\n            vertices[8] = new Point3d(0, -2, 0);\n            vertices[9] = new Point3d(2, 0, 0);\n            vertices[10] = new Point3d(0, 2, 0);\n            vertices[11] = new Point3d(-2, 0, 0);\n            vertices[12] = new Point3d(0, 0, -2);\n            vertices[13] = new Point3d(0, 0, 2);\n\n            Edge[] edges = new Edge[24];\n            edges[0] = new Edge(0, 8);\n            edges[1] = new Edge(1, 8);\n            edges[2] = new Edge(4, 8);\n            edges[3] = new Edge(5, 8);\n\n            edges[4] = new Edge(1, 9);\n            edges[5] = new Edge(2, 9);\n            edges[6] = new Edge(5, 9);\n            edges[7] = new Edge(6, 9);\n\n            edges[8] = new Edge(2, 10);\n            edges[9] = new Edge(3, 10);\n            edges[10] = new Edge(6, 10);\n            edges[11] = new Edge(7, 10);\n\n            edges[12] = new Edge(0, 11);\n            edges[13] = new Edge(3, 11);\n            edges[14] = new Edge(4, 11);\n            edges[15] = new Edge(7, 11);\n\n            edges[16] = new Edge(0, 12);\n            edges[17] = new Edge(1, 12);\n            edges[18] = new Edge(2, 12);\n            edges[19] = new Edge(3, 12);\n\n            edges[20] = new Edge(4, 13);\n            edges[21] = new Edge(5, 13);\n            edges[22] = new Edge(6, 13);\n            edges[23] = new Edge(7, 13);\n\n            Face[] faces = new Face[12];\n            faces[0] = new Face(4, new int[] { 0, 12, 1, 8 });\n            faces[1] = new Face(4, new int[] { 1, 12, 2, 9 });\n            faces[2] = new Face(4, new int[] { 2, 12, 3, 10 });\n            faces[3] = new Face(4, new int[] { 3, 12, 0, 11 });\n            faces[4] = new Face(4, new int[] { 4, 8, 5, 13 });\n            faces[5] = new Face(4, new int[] { 5, 9, 6, 13 });\n            faces[6] = new Face(4, new int[] { 6, 10, 7, 13 });\n            faces[7] = new Face(4, new int[] { 7, 11, 4, 13 });\n            faces[8] = new Face(4, new int[] { 0, 8, 4, 11 });\n            faces[9] = new Face(4, new int[] { 1, 9, 5, 8 });\n            faces[10] = new Face(4, new int[] { 2, 10, 6, 9 });\n            faces[11] = new Face(4, new int[] { 3, 11, 7, 10 });\n\n            return new ConvexPolyhedron(14, 24, 12, vertices, edges, faces);\n        }\n\n        /// <summary>\n        /// Creates Cuboctahedron\n        /// </summary>\n        public static ConvexPolyhedron Cuboctahedron()\n        {\n            Point3d[] vertices = new Point3d[12];\n            vertices[0] = new Point3d(0, -0.5, -0.5);\n            vertices[1] = new Point3d(0.5, 0, -0.5);\n            vertices[2] = new Point3d(0, 0.5, -0.5);\n            vertices[3] = new Point3d(-0.5, 0, -0.5);\n            vertices[4] = new Point3d(0, -0.5, 0.5);\n            vertices[5] = new Point3d(0.5, 0, 0.5);\n            vertices[6] = new Point3d(0, 0.5, 0.5);\n            vertices[7] = new Point3d(-0.5, 0, 0.5);\n            vertices[8] = new Point3d(-0.5, -0.5, 0);\n            vertices[9] = new Point3d(0.5, -0.5, 0);\n            vertices[10] = new Point3d(0.5, 0.5, 0);\n            vertices[11] = new Point3d(-0.5, 0.5, 0);\n\n\n            Edge[] edges = new Edge[24];\n            edges[0] = new Edge(0, 1);\n            edges[1] = new Edge(1, 2);\n            edges[2] = new Edge(2, 3);\n            edges[3] = new Edge(3, 0);\n\n            edges[4] = new Edge(4, 5);\n            edges[5] = new Edge(5, 6);\n            edges[6] = new Edge(6, 7);\n            edges[7] = new Edge(7, 4);\n\n            edges[8] = new Edge(0, 9);\n            edges[9] = new Edge(9, 4);\n            edges[10] = new Edge(4, 8);\n            edges[11] = new Edge(8, 0);\n\n            edges[12] = new Edge(1, 10);\n            edges[13] = new Edge(10, 5);\n            edges[14] = new Edge(5, 9);\n            edges[15] = new Edge(9, 1);\n\n            edges[16] = new Edge(2, 11);\n            edges[17] = new Edge(11, 6);\n            edges[18] = new Edge(6, 10);\n            edges[19] = new Edge(10, 2);\n\n            edges[20] = new Edge(3, 8);\n            edges[21] = new Edge(8, 7);\n            edges[22] = new Edge(7, 11);\n            edges[23] = new Edge(11, 3);\n\n            Face[] faces = new Face[14];\n            faces[0] = new Face(4, new int[] { 0, 3, 2, 1 });\n            faces[1] = new Face(4, new int[] { 4, 5, 6, 7 });\n            faces[2] = new Face(4, new int[] { 0, 9, 4, 8 });\n            faces[3] = new Face(4, new int[] { 1, 10, 5, 9 });\n            faces[4] = new Face(4, new int[] { 2, 11, 6, 10 });\n            faces[5] = new Face(4, new int[] { 3, 8, 7, 11 });\n\n            faces[6] = new Face(3, new int[] { 0, 1, 9 });\n            faces[7] = new Face(3, new int[] { 1, 2, 10 });\n            faces[8] = new Face(3, new int[] { 2, 3, 11 });\n            faces[9] = new Face(3, new int[] { 3, 0, 8 });\n\n            faces[10] = new Face(3, new int[] { 9, 5, 4 });\n            faces[11] = new Face(3, new int[] { 10, 6, 5 });\n            faces[12] = new Face(3, new int[] { 11, 7, 6 });\n            faces[13] = new Face(3, new int[] { 8, 4, 7 });\n\n            return new ConvexPolyhedron(12, 24, 14, vertices, edges, faces);\n        }\n\n        /// <summary>\n        /// Creates Rhombicuboctahedron\n        /// </summary>\n        public static ConvexPolyhedron Rhombicuboctahedron(double delta)\n        {\n            delta = delta / 2;\n\n            Point3d[] vertices = new Point3d[24];\n            vertices[0] = new Point3d(-0.5 + delta, -0.5 + delta, -0.5);\n            vertices[1] = new Point3d(0.5 - delta, -0.5 + delta, -0.5);\n            vertices[2] = new Point3d(0.5 - delta, 0.5 - delta, -0.5);\n            vertices[3] = new Point3d(-0.5 + delta, 0.5 - delta, -0.5);\n\n            vertices[4] = new Point3d(-0.5 + delta, -0.5 + delta, 0.5);\n            vertices[5] = new Point3d(0.5 - delta, -0.5 + delta, 0.5);\n            vertices[6] = new Point3d(0.5 - delta, 0.5 - delta, 0.5);\n            vertices[7] = new Point3d(-0.5 + delta, 0.5 - delta, 0.5);\n\n            vertices[8] = new Point3d(-0.5 + delta, -0.5, -0.5 + delta);\n            vertices[9] = new Point3d(0.5 - delta, -0.5, -0.5 + delta);\n            vertices[10] = new Point3d(0.5 - delta, -0.5, 0.5 - delta);\n            vertices[11] = new Point3d(-0.5 + delta, -0.5, 0.5 - delta);\n\n            vertices[12] = new Point3d(0.5, -0.5 + delta, -0.5 + delta);\n            vertices[13] = new Point3d(0.5, 0.5 - delta, -0.5 + delta);\n            vertices[14] = new Point3d(0.5, 0.5 - delta, 0.5 - delta);\n            vertices[15] = new Point3d(0.5, -0.5 + delta, 0.5 - delta);\n\n            vertices[16] = new Point3d(-0.5 + delta, 0.5, -0.5 + delta);\n            vertices[17] = new Point3d(0.5 - delta, 0.5, -0.5 + delta);\n            vertices[18] = new Point3d(0.5 - delta, 0.5, 0.5 - delta);\n            vertices[19] = new Point3d(-0.5 + delta, 0.5, 0.5 - delta);\n\n            vertices[20] = new Point3d(-0.5, -0.5 + delta, -0.5 + delta);\n            vertices[21] = new Point3d(-0.5, 0.5 - delta, -0.5 + delta);\n            vertices[22] = new Point3d(-0.5, 0.5 - delta, 0.5 - delta);\n            vertices[23] = new Point3d(-0.5, -0.5 + delta, 0.5 - delta);\n\n\n            Edge[] edges = new Edge[48];\n            edges[0] = new Edge(0, 1);\n            edges[1] = new Edge(1, 2);\n            edges[2] = new Edge(2, 3);\n            edges[3] = new Edge(3, 0);\n\n            edges[4] = new Edge(4, 5);\n            edges[5] = new Edge(5, 6);\n            edges[6] = new Edge(6, 7);\n            edges[7] = new Edge(7, 4);\n\n            edges[8] = new Edge(8, 9);\n            edges[9] = new Edge(9, 10);\n            edges[10] = new Edge(10, 11);\n            edges[11] = new Edge(11, 8);\n\n            edges[12] = new Edge(12, 13);\n            edges[13] = new Edge(13, 14);\n            edges[14] = new Edge(14, 15);\n            edges[15] = new Edge(15, 12);\n\n            edges[16] = new Edge(16, 17);\n            edges[17] = new Edge(17, 18);\n            edges[18] = new Edge(18, 19);\n            edges[19] = new Edge(19, 16);\n\n            edges[20] = new Edge(20, 21);\n            edges[21] = new Edge(21, 22);\n            edges[22] = new Edge(22, 23);\n            edges[23] = new Edge(23, 20);\n                        \n            edges[24] = new Edge(1, 12);\n            edges[25] = new Edge(12, 9);\n            edges[26] = new Edge(9, 1);\n\n            edges[27] = new Edge(2, 17);           \n            edges[28] = new Edge(17, 13);\n            edges[29] = new Edge(13, 2);\n\n            edges[30] = new Edge(3, 16);\n            edges[31] = new Edge(16, 21);        \n            edges[32] = new Edge(21, 3);\n\n            edges[33] = new Edge(0, 8);\n            edges[34] = new Edge(8, 20);\n            edges[35] = new Edge(20, 0); \n            \n            edges[36] = new Edge(5, 10);\n            edges[37] = new Edge(10, 15);\n            edges[38] = new Edge(15, 5);\n\n            edges[39] = new Edge(6, 14);           \n            edges[40] = new Edge(14, 18);\n            edges[41] = new Edge(18, 6);\n\n            edges[42] = new Edge(7, 22);\n            edges[43] = new Edge(22, 19);           \n            edges[44] = new Edge(19, 7);\n\n            edges[45] = new Edge(4, 23);\n            edges[46] = new Edge(23, 11);\n            edges[47] = new Edge(11, 4);\n\n            Face[] faces = new Face[26];\n            faces[0] = new Face(4, new int[] { 0, 3, 2, 1 });\n            faces[1] = new Face(4, new int[] { 4, 5, 6, 7 });\n            faces[2] = new Face(4, new int[] { 8, 9, 10, 11 });\n            faces[3] = new Face(4, new int[] { 12, 13, 14, 15 });\n            faces[4] = new Face(4, new int[] { 17, 16, 19, 18 });\n            faces[5] = new Face(4, new int[] { 21, 20, 23, 22 });\n\n            faces[6] = new Face(4, new int[] { 0, 1, 9, 8 });\n            faces[7] = new Face(4, new int[] { 1, 2, 13, 12 });\n            faces[8] = new Face(4, new int[] { 2, 3, 16, 17 });\n            faces[9] = new Face(4, new int[] { 0, 20, 21, 3 });\n\n            faces[10] = new Face(4, new int[] { 11, 10, 5, 4 });\n            faces[11] = new Face(4, new int[] { 15, 14, 6, 5 });\n            faces[12] = new Face(4, new int[] { 18, 19, 7, 6 });\n            faces[13] = new Face(4, new int[] { 22, 23, 4, 7 });\n\n            faces[14] = new Face(4, new int[] { 9, 12, 15, 10 });\n            faces[15] = new Face(4, new int[] { 13, 17, 18, 14 });\n            faces[16] = new Face(4, new int[] { 16, 21, 22, 19 });\n            faces[17] = new Face(4, new int[] { 20, 8, 11, 23 });\n\n            faces[18] = new Face(3, new int[] { 0, 8, 20 });\n            faces[19] = new Face(3, new int[] { 1, 12, 9 });\n            faces[20] = new Face(3, new int[] { 2, 17, 13 });\n            faces[21] = new Face(3, new int[] { 3, 21, 16 });\n            faces[22] = new Face(3, new int[] { 4, 23, 11 });\n            faces[23] = new Face(3, new int[] { 5, 10, 15 });\n            faces[24] = new Face(3, new int[] { 6, 14, 18 });\n            faces[25] = new Face(3, new int[] { 7, 19, 22 });\n\n            return new ConvexPolyhedron(24, 48, 26, vertices, edges, faces);\n        }\n\n\n        #endregion\n\n        #region \"Properties\"\n\n        /// <summary>\n        /// Center of mass.\n        /// </summary>\n        public Point3d Center\n        {\n            get\n            {\n                Point3d center = new Point3d(); ;\n                foreach (Point3d p in vertex)\n                {\n                    center += p;\n                }\n                return center / vertex.Length;\n            }\n        }\n\n        /// <summary>\n        /// Volume of the polyhedron.\n        /// </summary>\n        public double Volume\n        {\n            get\n            {\n                double volume = 0;\n                foreach (Face f in face)\n                {\n                    for (int i = 0; i < f.vertex.Length - 2; i++)\n                    {\n                        Vector3d v1 = new Vector3d(this.vertex[0], f.Vertex[0]);\n                        Vector3d v2 = new Vector3d(this.vertex[0], f.Vertex[i + 1]);\n                        Vector3d v3 = new Vector3d(this.vertex[0], f.Vertex[i + 2]);\n                        volume += v1 * (v2.Cross(v3));\n                    }\n                }\n                return volume / 6;\n            }\n        }\n\n        /// <summary>\n        /// Surface area of the polyhedron.\n        /// </summary>\n        public double Area\n        {\n            get\n            {\n                double area = 0;\n                foreach (Face f in face)\n                {\n                    area += f.Area;\n                }\n                return area;\n            }\n        }\n\n        /// <summary>\n        /// List of edges forming the polyhedron\n        /// </summary>\n        public List<Segment3d> ListOfEdges\n        {\n            get\n            {\n                lock (this)\n                {\n                    if (_list_e == null)\n                    {\n                        _list_e = new List<Segment3d> { };\n                        foreach (Edge e in edge)\n                        {\n                            _list_e.Add(new Segment3d(e.P1, e.P2));\n                        }\n                        return _list_e;\n                    }\n                    else\n                    {\n                        return _list_e;\n                    }\n                }\n            }\n        }\n\n        #endregion\n\n        /// <summary>\n        /// Creates copy of the object\n        /// </summary>\n        public ConvexPolyhedron Copy()\n        {\n            Point3d[] vertex_copy = new Point3d[vertex.Length];\n            Edge[] edge_copy = new Edge[edge.Length];\n            Face[] face_copy = new Face[face.Length];\n            Dictionary<Int32, Point3d> dict = new Dictionary<Int32, Point3d>();\n\n            for (int i = 0; i < vertex.Length; i++)\n            {\n                vertex_copy[i] = vertex[i].Copy();\n            }\n\n            for (int i = 0; i < edge.Length; i++)\n            {\n                edge_copy[i].p1 = edge[i].p1;\n                edge_copy[i].p2 = edge[i].p2;\n            }\n            for (int i = 0; i < face.Length; i++)\n            {\n                face_copy[i].normal = face[i].normal;\n                face_copy[i].numVertices = face[i].numVertices;\n                face_copy[i].vertex = new int[face[i].vertex.Length];\n\n                for (int j = 0; j < face[i].vertex.Length; j++)\n                {\n                    face_copy[i].vertex[j] = face[i].vertex[j];\n                }\n            }\n            return new ConvexPolyhedron(numVertices, numEdges, numFaces, vertex_copy, edge_copy, face_copy);\n        }\n\n        private void CheckFaceOrientation()\n        {\n            for (int i = 0; i < face.Length; i++)\n            {\n                Vector3d normal = face[i].normal;\n                Vector3d to_center = new Vector3d(face[i].Vertex[0], this.Center);\n                if (to_center * normal > 0)\n                {\n                    face[i] = ReverseFace(face[i]);\n                }\n            }\n        }\n\n        private Face ReverseFace(Face face)\n        {\n            int[] tmp = new int[face.numVertices];\n            for (int j = 0; j < face.numVertices; j++)\n            {\n                tmp[j] = face.vertex[face.numVertices - j - 1];\n            }\n            face.vertex = tmp;\n            face.UpdateNormal();\n            return face;\n        }\n\n\n        #region \"BoundingBox\"\n        /// <summary>\n        /// Return minimum bounding box.\n        /// </summary>\n        public Box3d MinimumBoundingBox\n        {\n            get\n            {\n                throw new NotImplementedException();\n            }\n        }\n\n        /// <summary>\n        /// Return Bounding Box in given coordinate system.\n        /// </summary>\n        public Box3d BoundingBox(Coord3d coord = null)\n        {\n            return Box3d.BoundingBox(vertex, coord);\n        }\n\n        /// <summary>\n        /// Return Axis Aligned Bounding Box (AABB).\n        /// </summary>\n        public AABB AABB()\n        {\n            if (_aabb == null)\n            {\n                _aabb = GeometRi.AABB.BoundingBox(vertex);\n            }\n            return _aabb;\n        }\n\n        /// <summary>\n        /// Return bounding sphere.\n        /// </summary>\n        public Sphere BoundingSphere\n        {\n            get\n            {\n                throw new NotImplementedException();\n            }\n\n        }\n        #endregion\n\n\n        #region \"Distance\"\n\n        /// <summary>\n        /// Distance from polyhedron to point (zero will be returned for point located inside polyhedron)\n        /// </summary>\n        public double DistanceTo(Point3d p)\n        {\n            if (p.BelongsTo(this))\n            {\n                return 0;\n            }\n\n            // test faces\n            for (int i = 0; i < numFaces; i++)\n            {\n                // test only visible faces\n                double point_face_plane_dist = face[i].normal * new Vector3d(face[i].Vertex[0], p);\n                if (point_face_plane_dist < 0)\n                {\n                    continue;\n                }\n\n                Point3d projection_point =  p - point_face_plane_dist * face[i].normal;\n                \n                // test if projection of point is inside the face\n                bool inside = true;\n                for (int l = 0; l < this.face[i].vertex.Length; l++)\n                {\n                    Vector3d edge = new Vector3d(this.face[i].Vertex[l], this.face[i].Vertex[0]);\n                    if (l < this.face[i].vertex.Length - 1)\n                    {\n                        edge = new Vector3d(this.face[i].Vertex[l], this.face[i].Vertex[l + 1]);\n                    }\n                    Vector3d v = new Vector3d(this.face[i].Vertex[l], projection_point);\n                    if (edge.Cross(v).Dot(this.face[i].normal) < 0)\n                    {\n                        // projection outside of face\n                        inside = false;\n                        break;\n                    }\n                }\n                if (inside)\n                {\n                    return point_face_plane_dist;\n                }\n            }\n\n            // test edges\n            double dist = double.PositiveInfinity;\n\n            foreach (Segment3d s1 in ListOfEdges)\n            {\n                double tmp_dist = p.DistanceTo(s1);\n                if (tmp_dist < dist)\n                {\n                    dist = tmp_dist;\n                }\n            }\n\n            return dist;\n        }\n\n        /// <summary>\n        /// Distance from polyhedron to circle (zero will be returned for circle located inside polyhedron)\n        /// </summary>\n        public double DistanceTo(Circle3d c)\n        {\n            if (c._point.BelongsTo(this))\n            {\n                return 0;\n            }\n\n            double dist = double.PositiveInfinity;\n\n            for (int i = 0; i < numFaces; i++)\n            {\n                // test only visible faces\n                if (face[i].normal * new Vector3d(face[i].Vertex[0], c._point) < 0)\n                {\n                    continue;\n                }\n\n                for (int j = 0; j < face[i].vertex.Length - 2; j++)\n                {\n                    Triangle t = new Triangle(face[i].Vertex[0], face[i].Vertex[j + 1], face[i].Vertex[j + 2]);\n                    double tmp_dist = t.DistanceTo(c);\n                    if (tmp_dist <= GeometRi3D.Tolerance)\n                    {\n                        return tmp_dist;\n                    }\n                    if (tmp_dist < dist)\n                    {\n                        dist = tmp_dist;\n                    }\n                }\n\n            }\n            return dist;\n        }\n\n        /// <summary>\n        /// Distance from polyhedron to sphere\n        /// </summary>\n        public double DistanceTo(Sphere s)\n        {\n            double dist = this.DistanceTo(s.Center) - s.R;\n            return dist < 0 ? 0 : dist;\n        }\n\n        /// <summary>\n        /// Distance between two polyhedrons\n        /// </summary>\n        /// <param name=\"c\">Target polyhedron</param>\n        public double DistanceTo(ConvexPolyhedron c)\n        {\n            // Use \"Method of Separating Axes\" to test intersection combined with distance calculation\n\n            // Intersection of Convex Objects: The Method of Separating Axes\n            // David Eberly, Geometric Tools, Redmond WA 98052\n            // Creative Commons Attribution 4.0 International License\n\n            double dist = double.PositiveInfinity;\n            bool intersecting = true;\n\n            // Test faces of this CP for separation. Because of the counterclockwise ordering,\n            // the projection interval for this CP is (-inf, 0].\n            // Determine whether 'c' is on the positive side of the line\n            for (int i = 0; i < this.numFaces; i++)\n            {\n                Vector3d N = this.face[i].normal;\n                if (WhichSide(c.vertex, this.face[i].Vertex[0], N) > 0)\n                {\n                    // 'c' is entirely on the positive side of the line P + t * N\n                    // Calculate min projection distance to face's plane\n                    intersecting = false;\n                    double square_proj_dist = double.PositiveInfinity;\n                    Point3d best_proj_point = this.face[i].Vertex[0];\n                    Point3d target_point = this.face[i].Vertex[0];\n\n                    Plane3d plane = new Plane3d(this.face[i].Vertex[0], this.face[i].normal);\n                    foreach (Point3d point in c.vertex)\n                    {\n                        Point3d projection = point.ProjectionTo(plane);\n                        double tmp_dist = projection.DistanceSquared(point);\n                        if (tmp_dist < square_proj_dist)\n                        {\n                            square_proj_dist = tmp_dist;\n                            best_proj_point = projection;\n                            target_point = point;\n                        }\n                    }\n                    // test if best projection of c.vertex is inside the face\n                    bool inside = true;\n                    for (int l = 0; l < this.face[i].vertex.Length; l++)\n                    {\n                        Vector3d edge = new Vector3d(this.face[i].Vertex[l], this.face[i].Vertex[0]);\n                        if (l < this.face[i].vertex.Length - 1)\n                        {\n                            edge = new Vector3d(this.face[i].Vertex[l], this.face[i].Vertex[l + 1]);\n                        }\n                        Vector3d v = new Vector3d(this.face[i].Vertex[l], best_proj_point);\n                        if (edge.Cross(v).Dot(this.face[i].normal) < 0)\n                        {\n                            // projection outside of face\n                            inside = false;\n                            break;\n                        }\n\n                    }\n                    if (inside)\n                    {\n                        double tmp_dist = Math.Sqrt(square_proj_dist);\n                        if (tmp_dist < dist)\n                        {\n                            dist = tmp_dist;\n                            return dist;\n                        }\n                    }\n                }\n            }\n\n            // Test faces 'c' for separation. Because of the counterclockwise ordering,\n            // the projection interval for 'c' is (-inf, 0].\n            // Determine whether this CP is on the positive side of the line\n            for (int i = 0; i < c.numFaces; i++)\n            {\n                Vector3d N = c.face[i].normal;\n                if (WhichSide(this.vertex, c.face[i].Vertex[0], N) > 0)\n                {\n                    // this CP is entirely on the positive side of the line P + t * N\n                    // Calculate min projection distance to face's plane\n                    intersecting = false;\n                    double square_proj_dist = double.PositiveInfinity;\n                    Point3d best_proj_point = c.face[i].Vertex[0];\n                    Point3d target_point = c.face[i].Vertex[0];\n\n                    Plane3d plane = new Plane3d(c.face[i].Vertex[0], c.face[i].normal);\n                    foreach (Point3d point in this.vertex)\n                    {\n                        Point3d projection = point.ProjectionTo(plane);\n                        double tmp_dist = projection.DistanceSquared(point);\n                        if (tmp_dist < square_proj_dist)\n                        {\n                            square_proj_dist = tmp_dist;\n                            best_proj_point = projection;\n                            target_point = point;\n                        }\n                    }\n                    // test if best projection of this.vertex is inside the face\n                    bool inside = true;\n                    for (int l = 0; l < c.face[i].vertex.Length; l++)\n                    {\n                        Vector3d edge = new Vector3d(c.face[i].Vertex[l], c.face[i].Vertex[0]);\n                        if (l < c.face[i].vertex.Length - 1)\n                        {\n                            edge = new Vector3d(c.face[i].Vertex[l], c.face[i].Vertex[l + 1]);\n                        }\n                        Vector3d v = new Vector3d(c.face[i].Vertex[l], best_proj_point);\n                        if (edge.Cross(v).Dot(c.face[i].normal) < 0)\n                        {\n                            // projection outside of face\n                            inside = false;\n                            break;\n                        }\n\n                    }\n                    if (inside)\n                    {\n                        double tmp_dist = Math.Sqrt(square_proj_dist);\n                        if (tmp_dist < dist)\n                        {\n                            dist = tmp_dist;\n                            return dist;\n                        }\n                    }\n\n                }\n            }\n\n            if (!intersecting)\n            {\n                // Polyhedrons are not intersecting\n                // Compare edges distance\n                foreach (Segment3d s1 in ListOfEdges)\n                {\n                    foreach (Segment3d s2 in c.ListOfEdges)\n                    {\n                        double tmp_dist = s1.DistanceTo(s2);\n                        if (tmp_dist < dist)\n                        {\n                            dist = tmp_dist;\n                        }\n                    }\n                }\n                return dist;\n            }\n\n            // Test cross products of pairs of edge directions\n            // one edge direction from each polyhedron\n\n            foreach (Segment3d s1 in ListOfEdges)\n            {\n                Point3d D0 = s1.P2 - s1.P1;\n                foreach (Segment3d s2 in c.ListOfEdges)\n                {\n                    Point3d D1 = s2.P2 - s2.P1;\n                    Point3d N = D0.Cross(D1);\n\n                    if (N.X != 0 || N.Y != 0 || N.Z != 0)\n                    {\n                        int side0 = WhichSide(this.vertex, s1.P1, N, 1e-16);\n                        if (side0 == 0)\n                        {\n                            continue;\n                        }\n                        int side1 = WhichSide(c.vertex, s1.P1, N, 1e-16);\n                        if (side1 == 0)\n                        {\n                            continue;\n                        }\n\n                        if (side0 * side1 < 0)\n                        {\n                            // The projections of this CP and 'c' onto the line P + t * N are on opposite sides of the projection of P.\n                            intersecting = false;\n                            double tmp_dist = s1.DistanceTo(s2);\n                            if (tmp_dist < dist)\n                            {\n                                dist = tmp_dist;\n                            }\n                        }\n                    }\n                }\n            }\n\n            if (intersecting)\n            {\n                return 0;\n            }\n            else\n            {\n                return dist;\n            }\n\n        }\n\n\n        /// <summary>\n        /// Distance between two polyhedrons\n        /// <para> The output points are valid only in case of non-intersecting objects.</para>\n        /// </summary>\n        /// <param name=\"c\">Target polyhedron</param>\n        /// <param name=\"point_on_this_cp\">Closest point on this convex polyhedron</param>\n        /// <param name=\"point_on_target_cp\">Closest point on target convex polyhedron</param>\n        public double DistanceTo(ConvexPolyhedron c, out Point3d point_on_this_cp, out Point3d point_on_target_cp)\n        {\n            // Use \"Method of Separating Axes\" to test intersection combined with distance calculation\n\n            // Intersection of Convex Objects: The Method of Separating Axes\n            // David Eberly, Geometric Tools, Redmond WA 98052\n            // Creative Commons Attribution 4.0 International License\n\n            double dist = double.PositiveInfinity;\n            bool intersecting = true;\n            Point3d c1 = new Point3d();\n            Point3d c2 = new Point3d();\n            point_on_this_cp = c1;\n            point_on_target_cp = c2;\n\n            // Test faces of this CP for separation. Because of the counterclockwise ordering,\n            // the projection interval for this CP is (-inf, 0].\n            // Determine whether 'c' is on the positive side of the line\n            for (int i = 0; i < this.numFaces; i++)\n            {\n                Vector3d N = this.face[i].normal;\n                if (WhichSide(c.vertex, this.face[i].Vertex[0], N) > 0)\n                {\n                    // 'c' is entirely on the positive side of the line P + t * N\n                    // Calculate min projection distance to face's plane\n                    intersecting = false;\n                    double square_proj_dist = double.PositiveInfinity;\n                    Point3d best_proj_point = this.face[i].Vertex[0];\n                    Point3d target_point = this.face[i].Vertex[0];\n\n                    Plane3d plane = new Plane3d(this.face[i].Vertex[0], this.face[i].normal);\n                    foreach (Point3d point in c.vertex)\n                    {\n                        Point3d projection = point.ProjectionTo(plane);\n                        double tmp_dist = projection.DistanceSquared(point);\n                        if (tmp_dist < square_proj_dist)\n                        {\n                            square_proj_dist = tmp_dist;\n                            best_proj_point = projection;\n                            target_point = point;\n                        }\n                    }\n                    // test if best projection of c.vertex is inside the face\n                    bool inside = true;\n                    for (int l = 0; l < this.face[i].vertex.Length; l++)\n                    {\n                        Vector3d edge = new Vector3d(this.face[i].Vertex[l], this.face[i].Vertex[0]);\n                        if (l < this.face[i].vertex.Length - 1)\n                        {\n                            edge = new Vector3d(this.face[i].Vertex[l], this.face[i].Vertex[l + 1]);\n                        }\n                        Vector3d v = new Vector3d(this.face[i].Vertex[l], best_proj_point);\n                        if (edge.Cross(v).Dot(this.face[i].normal) < 0)\n                        {\n                            // projection outside of face\n                            inside = false;\n                            break;\n                        }\n\n                    }\n                    if (inside)\n                    {\n                        double tmp_dist = Math.Sqrt(square_proj_dist);\n                        if (tmp_dist < dist) { \n                            dist = tmp_dist;\n                            point_on_this_cp = best_proj_point;\n                            point_on_target_cp = target_point;\n                            return dist;\n                        }\n                    }\n                }\n            }\n\n            // Test faces 'c' for separation. Because of the counterclockwise ordering,\n            // the projection interval for 'c' is (-inf, 0].\n            // Determine whether this CP is on the positive side of the line\n            for (int i = 0; i < c.numFaces; i++)\n            {\n                Vector3d N = c.face[i].normal;\n                if (WhichSide(this.vertex, c.face[i].Vertex[0], N) > 0)\n                {\n                    // this CP is entirely on the positive side of the line P + t * N\n                    // Calculate min projection distance to face's plane\n                    intersecting = false;\n                    double square_proj_dist = double.PositiveInfinity;\n                    Point3d best_proj_point = c.face[i].Vertex[0];\n                    Point3d target_point = c.face[i].Vertex[0];\n\n                    Plane3d plane = new Plane3d(c.face[i].Vertex[0], c.face[i].normal);\n                    foreach (Point3d point in this.vertex)\n                    {\n                        Point3d projection = point.ProjectionTo(plane);\n                        double tmp_dist = projection.DistanceSquared(point);\n                        if (tmp_dist < square_proj_dist)\n                        {\n                            square_proj_dist = tmp_dist;\n                            best_proj_point = projection;\n                            target_point = point;\n                        }\n                    }\n                    // test if best projection of this.vertex is inside the face\n                    bool inside = true;\n                    for (int l = 0; l < c.face[i].vertex.Length; l++)\n                    {\n                        Vector3d edge = new Vector3d(c.face[i].Vertex[l], c.face[i].Vertex[0]);\n                        if (l < c.face[i].vertex.Length - 1)\n                        {\n                            edge = new Vector3d(c.face[i].Vertex[l], c.face[i].Vertex[l + 1]);\n                        }\n                        Vector3d v = new Vector3d(c.face[i].Vertex[l], best_proj_point);\n                        if (edge.Cross(v).Dot(c.face[i].normal) < 0)\n                        {\n                            // projection outside of face\n                            inside = false;\n                            break;\n                        }\n\n                    }\n                    if (inside)\n                    {\n                        double tmp_dist = Math.Sqrt(square_proj_dist);\n                        if (tmp_dist < dist)\n                        {\n                            dist = tmp_dist;\n                            point_on_this_cp = target_point;\n                            point_on_target_cp = best_proj_point;\n                            return dist;\n                        }\n                    }\n\n                }\n            }\n\n            if (! intersecting)\n            {\n                // Polyhedrons are not intersecting\n                // Compare edges distance\n                foreach (Segment3d s1 in ListOfEdges)\n                {\n                    foreach (Segment3d s2 in c.ListOfEdges)\n                    {\n                        double tmp_dist = s1.DistanceTo(s2, out c1, out c2);\n                        if (tmp_dist < dist)\n                        {\n                            dist = tmp_dist;\n                            point_on_this_cp = c1;\n                            point_on_target_cp = c2;\n                        }\n                    }\n                }\n                return dist;\n            }\n\n            // Test cross products of pairs of edge directions\n            // one edge direction from each polyhedron\n\n            foreach (Segment3d s1 in ListOfEdges)\n            {\n                Point3d D0 = s1.P2 - s1.P1;\n                foreach (Segment3d s2 in c.ListOfEdges)\n                {\n                    Point3d D1 = s2.P2 - s2.P1;\n                    Point3d N = D0.Cross(D1);\n\n                    if (N.X != 0 || N.Y != 0 || N.Z != 0)\n                    {\n                        int side0 = WhichSide(this.vertex, s1.P1, N, 1e-16);\n                        if (side0 == 0)\n                        {\n                            continue;\n                        }\n                        int side1 = WhichSide(c.vertex, s1.P1, N, 1e-16);\n                        if (side1 == 0)\n                        {\n                            continue;\n                        }\n\n                        if (side0 * side1 < 0)\n                        {\n                            // The projections of this CP and 'c' onto the line P + t * N are on opposite sides of the projection of P.\n                            intersecting = false;\n                            double tmp_dist = s1.DistanceTo(s2, out c1, out c2);\n                            if (tmp_dist < dist)\n                            {\n                                dist = tmp_dist;\n                                point_on_this_cp = c1;\n                                point_on_target_cp = c2;\n                            }\n                        }\n                    }\n                }\n            }\n\n            if (intersecting)\n            {\n                return 0;\n            }\n            else\n            {\n                return dist;\n            }\n        }\n\n\n        /// <summary>\n        /// Distance from polyhedron to triangle\n        /// </summary>\n        public double DistanceTo(Triangle t)\n        {\n            return this.DistanceTo(t, out Point3d p1, out Point3d p2);\n        }\n\n        /// <summary>\n        /// Distance between polyhedron and tringle\n        /// <para> The output points are valid only in case of non-intersecting objects.</para>\n        /// </summary>\n        /// <param name=\"t\">Target triangle</param>\n        /// <param name=\"point_on_polyhedron\">Closest point on this convex polyhedron</param>\n        /// <param name=\"point_on_triangle\">Closest point on target triangle</param>\n        public double DistanceTo(Triangle t, out Point3d point_on_polyhedron, out Point3d point_on_triangle)\n        {\n            // Using algorithm of separating axes\n\n            double dist = double.PositiveInfinity;\n            bool intersecting = true;\n            Point3d c1 = new Point3d();\n            Point3d c2 = new Point3d();\n            point_on_polyhedron = c1;\n            point_on_triangle = c2;\n\n            // Test faces of this CP for separation. Because of the counterclockwise ordering,\n            // the projection interval for this CP is (-inf, 0].\n            // Determine whether 'c' is on the positive side of the line\n            Point3d[] triangle_points = { t.A, t.B, t.C };\n            for (int i = 0; i < this.numFaces; i++)\n            {\n                Vector3d N = this.face[i].normal;\n                if (WhichSide(triangle_points, this.face[i].Vertex[0], N) > 0)\n                {\n                    // 't' is entirely on the positive side of the line P + t * N\n                    // Calculate min projection distance to face's plane\n                    intersecting = false;\n                    double square_proj_dist = double.PositiveInfinity;\n                    Point3d best_proj_point = this.face[i].Vertex[0];\n                    Point3d target_point = this.face[i].Vertex[0];\n\n                    Plane3d plane = new Plane3d(this.face[i].Vertex[0], this.face[i].normal);\n                    foreach (Point3d point in triangle_points)\n                    {\n                        Point3d projection = point.ProjectionTo(plane);\n                        double tmp_dist = projection.DistanceSquared(point);\n                        if (tmp_dist < square_proj_dist)\n                        {\n                            square_proj_dist = tmp_dist;\n                            best_proj_point = projection;\n                            target_point = point;\n                        }\n                    }\n                    // test if best projection of c.vertex is inside the face\n                    bool inside = true;\n                    for (int l = 0; l < this.face[i].vertex.Length; l++)\n                    {\n                        Vector3d edge = new Vector3d(this.face[i].Vertex[l], this.face[i].Vertex[0]);\n                        if (l < this.face[i].vertex.Length - 1)\n                        {\n                            edge = new Vector3d(this.face[i].Vertex[l], this.face[i].Vertex[l + 1]);\n                        }\n                        Vector3d v = new Vector3d(this.face[i].Vertex[l], best_proj_point);\n                        if (edge.Cross(v).Dot(this.face[i].normal) < 0)\n                        {\n                            // projection outside of face\n                            inside = false;\n                            break;\n                        }\n\n                    }\n                    if (inside)\n                    {\n                        double tmp_dist = Math.Sqrt(square_proj_dist);\n                        if (tmp_dist < dist)\n                        {\n                            dist = tmp_dist;\n                            point_on_polyhedron = best_proj_point;\n                            point_on_triangle = target_point;\n                            return dist;\n                        }\n                    }\n                }\n            }\n\n            // Test both faces of triangle for separation.\n            for (int i = -1; i < 2; i += 2)\n            {\n                Vector3d N = i * t.Normal;\n                if (WhichSide(this.vertex, t.A, N) > 0)\n                {\n                    // this CP is entirely on the positive side of the line P + t * N\n                    // Calculate min projection distance to face's plane\n                    intersecting = false;\n                    double square_proj_dist = double.PositiveInfinity;\n                    Point3d best_proj_point = t.A;\n                    Point3d target_point = t.A;\n\n                    Plane3d plane = t.Plane;\n                    foreach (Point3d point in this.vertex)\n                    {\n                        Point3d projection = point.ProjectionTo(plane);\n                        double tmp_dist = projection.DistanceSquared(point);\n                        if (tmp_dist < square_proj_dist)\n                        {\n                            square_proj_dist = tmp_dist;\n                            best_proj_point = projection;\n                            target_point = point;\n                        }\n                    }\n                    // test if best projection of this.vertex is inside the face\n                    bool inside = true;\n                    for (int j0 = 2, j1 = 0; j1 < 3; j0 = j1++)\n                    {\n                        Vector3d edge = new Vector3d(triangle_points[j0], triangle_points[j1]);\n                        Vector3d v = new Vector3d(triangle_points[j0], best_proj_point);\n                        if (edge.Cross(v).Dot(plane.Normal) < 0)\n                        {\n                            // projection outside of face\n                            inside = false;\n                            break;\n                        }\n\n                    }\n                    if (inside)\n                    {\n                        double tmp_dist = Math.Sqrt(square_proj_dist);\n                        if (tmp_dist < dist)\n                        {\n                            dist = tmp_dist;\n                            point_on_polyhedron = target_point;\n                            point_on_triangle = best_proj_point;\n                            return dist;\n                        }\n                    }\n\n                }\n            }\n\n            if (!intersecting)\n            {\n                // Polyhedrons are not intersecting\n                // Compare edges distance\n                foreach (Segment3d s1 in ListOfEdges)\n                {\n                    for (int j0 = 2, j1 = 0; j1 < 3; j0 = j1++)\n                    {\n                        Segment3d s2 = new Segment3d(triangle_points[j0], triangle_points[j1]);\n                        double tmp_dist = s1.DistanceTo(s2, out c1, out c2);\n                        if (tmp_dist < dist)\n                        {\n                            dist = tmp_dist;\n                            point_on_polyhedron = c1;\n                            point_on_triangle = c2;\n                        }\n                    }\n                }\n                return dist;\n            }\n\n            // Test cross products of pairs of edge directions\n            // one edge direction from each polyhedron\n            foreach (Segment3d s1 in ListOfEdges)\n            {\n                Point3d D0 = s1.P2 - s1.P1;\n                for (int j0 = 2, j1 = 0; j1 < 3; j0 = j1++)\n                {\n                    Point3d D1 = triangle_points[j1] - triangle_points[j0];\n                    Point3d N = D0.Cross(D1);\n\n                    if (N.X != 0 || N.Y != 0 || N.Z != 0)\n                    {\n                        int side0 = WhichSide(this.vertex, s1.P1, N, 1e-16);\n                        if (side0 == 0)\n                        {\n                            continue;\n                        }\n                        int side1 = WhichSide(triangle_points, s1.P1, N, 1e-16);\n                        if (side1 == 0)\n                        {\n                            continue;\n                        }\n\n                        if (side0 * side1 < 0)\n                        {\n                            // The projections of this CP and 'c' onto the line P + t * N are on opposite sides of the projection of P.\n                            intersecting = false;\n                            Segment3d s2 = new Segment3d(triangle_points[j0], triangle_points[j1]);\n                            double tmp_dist = s1.DistanceTo(s2, out c1, out c2);\n                            if (tmp_dist < dist)\n                            {\n                                dist = tmp_dist;\n                                point_on_polyhedron = c1;\n                                point_on_triangle = c2;\n                            }\n                        }\n                    }\n                }\n            }\n\n            if (intersecting)\n            {\n                return 0;\n            }\n            else\n            {\n                return dist;\n            }\n        }\n\n        /// <summary>\n        /// Distance from polyhedron to segment\n        /// <para> The output points are valid only in case of non-intersecting objects.</para>\n        /// </summary>\n        /// <param name=\"c\">Target polyhedron</param>\n        /// <param name=\"point_on_polyhedron\">Closest point on polyhedron</param>\n        /// <param name=\"point_on_segment\">Closest point on segment</param>\n        public double DistanceTo(Segment3d c, out Point3d point_on_polyhedron, out Point3d point_on_segment)\n        {\n            // Using algorithm of separating axes\n\n            double dist = double.PositiveInfinity;\n            bool intersecting = true;\n            Point3d c1 = new Point3d();\n            Point3d c2 = new Point3d();\n            point_on_polyhedron = c1;\n            point_on_segment = c2;\n\n            // Test faces of this CP for separation. Because of the counterclockwise ordering,\n            // the projection interval for this CP is (-inf, 0].\n            // Determine whether 'c' is on the positive side of the line\n            Point3d[] segment_points = { c.P1, c.P2 };\n            for (int i = 0; i < this.numFaces; i++)\n            {\n                Vector3d N = this.face[i].normal;\n                if (WhichSide(segment_points, this.face[i].Vertex[0], N) > 0)\n                {\n                    // 'c' is entirely on the positive side of the line P + t * N\n                    // Calculate min projection distance to face's plane\n                    intersecting = false;\n                    double square_proj_dist = double.PositiveInfinity;\n                    Point3d best_proj_point = this.face[i].Vertex[0];\n                    Point3d target_point = this.face[i].Vertex[0];\n\n                    Plane3d plane = new Plane3d(this.face[i].Vertex[0], this.face[i].normal);\n                    foreach (Point3d point in segment_points)\n                    {\n                        Point3d projection = point.ProjectionTo(plane);\n                        double tmp_dist = projection.DistanceSquared(point);\n                        if (tmp_dist < square_proj_dist)\n                        {\n                            square_proj_dist = tmp_dist;\n                            best_proj_point = projection;\n                            target_point = point;\n                        }\n                    }\n                    // test if best projection of c.vertex is inside the face\n                    bool inside = true;\n                    for (int l = 0; l < this.face[i].vertex.Length; l++)\n                    {\n                        Vector3d edge = new Vector3d(this.face[i].Vertex[l], this.face[i].Vertex[0]);\n                        if (l < this.face[i].vertex.Length - 1)\n                        {\n                            edge = new Vector3d(this.face[i].Vertex[l], this.face[i].Vertex[l + 1]);\n                        }\n                        Vector3d v = new Vector3d(this.face[i].Vertex[l], best_proj_point);\n                        if (edge.Cross(v).Dot(this.face[i].normal) < 0)\n                        {\n                            // projection outside of face\n                            inside = false;\n                            break;\n                        }\n\n                    }\n                    if (inside)\n                    {\n                        double tmp_dist = Math.Sqrt(square_proj_dist);\n                        if (tmp_dist < dist)\n                        {\n                            dist = tmp_dist;\n                            point_on_polyhedron = best_proj_point;\n                            point_on_segment = target_point;\n                            return dist;\n                        }\n                    }\n                }\n            }\n\n            if (!intersecting)\n            {\n                // Polyhedron and segment are not intersecting\n                // Compare edges distance\n                foreach (Segment3d s in ListOfEdges)\n                {\n                    double tmp_dist = s.DistanceTo(c, out c1, out c2);\n                    if (tmp_dist < dist)\n                    {\n                        dist = tmp_dist;\n                        point_on_polyhedron = c1;\n                        point_on_segment = c2;\n                    }\n                }\n                return dist;\n            }\n\n            // Test cross products of segment and edges\n            foreach (Segment3d s in ListOfEdges)\n            {\n                Point3d D0 = s.P2 - s.P1;\n                Point3d D1 = c.P2 - c.P1;\n                Point3d N = D0.Cross(D1);\n\n                if (N.X != 0 || N.Y != 0 || N.Z != 0)\n                {\n                    int side0 = WhichSide(this.vertex, s.P1, N, 1e-16);\n                    if (side0 == 0)\n                    {\n                        continue;\n                    }\n                    int side1 = WhichSide(segment_points, s.P1, N, 1e-16);\n                    if (side1 == 0)\n                    {\n                        continue;\n                    }\n\n                    if (side0 * side1 < 0)\n                    {\n                        // The projections of this CP and 'c' onto the line P + t * N are on opposite sides of the projection of P.\n                        intersecting = false;\n                        double tmp_dist = s.DistanceTo(c, out c1, out c2);\n                        if (tmp_dist < dist)\n                        {\n                            dist = tmp_dist;\n                            point_on_polyhedron = c1;\n                            point_on_segment = c2;\n                        }\n                    }\n                }\n            }\n\n            if (intersecting)\n            {\n                return 0;\n            }\n            else\n            {\n                return dist;\n            }\n        }\n\n        /// <summary>\n        /// Distance from polyhedron to segment\n        /// </summary>\n        public double DistanceTo(Segment3d s)\n        {\n            return DistanceTo(s, out Point3d p1, out Point3d p2);\n        }\n\n        internal Point3d _get_common_point(ConvexPolyhedron cp)\n        {\n            // test edges of this cp\n            for (int i = 0; i < this.numEdges; i++)\n            {\n                Segment3d s1 = new Segment3d(this.vertex[this.edge[i].p1], this.vertex[this.edge[i].p2]);\n                for (int k = 0; k < cp.numFaces; k++)\n                {\n                    for (int l = 0; l < cp.face[k].vertex.Length - 2; l++)\n                    {\n                        Triangle t2 = new Triangle(cp.face[k].Vertex[0], cp.face[k].Vertex[l + 1], cp.face[k].Vertex[l + 2]);\n\n                        Point3d p1, p2;\n                        double tmp_dist = s1.DistanceTo(t2, out p1, out p2);\n                        if (tmp_dist == 0)\n                        {\n                            return p1;\n                        }\n                    }\n\n                }\n            }\n\n            // test edges of target cp\n            for (int i = 0; i < cp.numEdges; i++)\n            {\n                Segment3d s1 = new Segment3d(cp.vertex[cp.edge[i].p1], cp.vertex[cp.edge[i].p2]);\n                for (int k = 0; k < this.numFaces; k++)\n                {\n                    for (int l = 0; l < this.face[k].vertex.Length - 2; l++)\n                    {\n                        Triangle t2 = new Triangle(this.face[k].Vertex[0], this.face[k].Vertex[l + 1], this.face[k].Vertex[l + 2]);\n\n                        Point3d p1, p2;\n                        double tmp_dist = s1.DistanceTo(t2, out p1, out p2);\n                        if (tmp_dist == 0)\n                        {\n                            return p1;\n                        }\n                    }\n\n                }\n            }\n\n            return null;\n        }\n\n\n\n\n\n        #endregion\n\n\n        #region \"Intersection\"\n\n        /// <summary>\n        /// Intersection check between two polyhedrons.\n        /// </summary>\n        public bool Intersects(ConvexPolyhedron c)\n        {\n\n            // Algorithm from:\n            // Intersection of Convex Objects: The Method of Separating Axes\n            // David Eberly, Geometric Tools, Redmond WA 98052\n            // Creative Commons Attribution 4.0 International License\n\n            // Test faces of this CP for separation. Because of the counterclockwise ordering,\n            // the projection interval for this CP is (-inf, 0].\n            // Determine whether 'c' is on the positive side of the line\n            for (int i = 0; i < this.numFaces; i++)\n            {\n                if (WhichSide(c.vertex, this.face[i].Vertex[0], this.face[i].normal) > 0)\n                {\n                    // 'c' is entirely on the positive side of the line P + t * N\n                    return false;\n                }\n            }\n\n            // Test faces 'c' for separation. Because of the counterclockwise ordering,\n            // the projection interval for 'c' is (-inf, 0].\n            // Determine whether this CP is on the positive side of the line\n            for (int i = 0; i < c.numFaces; i++)\n            {\n                if (WhichSide(this.vertex, c.face[i].Vertex[0], c.face[i].normal) > 0)\n                {\n                    // this CP is entirely on the positive side of the line P + t * N\n                    return false;\n                }\n            }\n\n            // Test cross products of pairs of edge directions\n            // one edge direction from each polyhedron\n            for (int i = 0; i < this.numEdges; i++)\n            {\n                Point3d D0 = this.edge[i].P2 - this.edge[i].P1;\n                for (int j = 0; j < c.numEdges; j++)\n                {\n                    Point3d D1 = c.edge[j].P2 - c.edge[j].P1;\n                    Point3d N = D0.Cross(D1);\n\n                    if (N.X != 0 || N.Y != 0 || N.Z != 0)\n                    {\n                        int side0 = WhichSide(this.vertex, this.edge[i].P1, N, 1e-16);\n                        if (side0 == 0)\n                        {\n                            continue;\n                        }\n                        int side1 = WhichSide(c.vertex, this.edge[i].P1, N, 1e-16);\n                        if (side1 == 0)\n                        {\n                            continue;\n                        }\n\n                        if (side0 * side1 < 0)\n                        {\n                            // The projections of this CP and 'c' onto the line P + t * N are on opposite sides of the projection of P.\n                            return false;\n                        }\n                    }\n                }\n            }\n\n            return true;\n        }\n\n\n        /// <summary>\n        /// Intersection check between polyhedron and segment.\n        /// Behaviour for touching objects is undefined.\n        /// </summary>\n        public bool Intersects(Segment3d c)\n        {\n            // Using algorithm of separating axes\n\n            // Test faces of this CP for separation. Because of the counterclockwise ordering,\n            // the projection interval for this CP is (-inf, 0].\n            // Determine whether 'c' is on the positive side of the line\n            Point3d[] segment_points = { c.P1, c.P2 };\n            for (int i = 0; i < this.numFaces; i++)\n            {\n                if (WhichSide(segment_points, this.face[i].Vertex[0], this.face[i].normal) > 0)\n                {\n                    // 'c' is entirely on the positive side of the line P + t * N\n                    return false;\n                }\n            }\n\n            // Test cross products of segment and edges\n            for (int i = 0; i < this.numEdges; i++)\n            {\n                Point3d D0 = this.edge[i].P2 - this.edge[i].P1;\n                Point3d D1 = c.P2 - c.P1;\n                Point3d N = D0.Cross(D1);\n\n                if (N.X != 0 || N.Y != 0 || N.Z != 0)\n                {\n                    int side0 = WhichSide(this.vertex, this.edge[i].P1, N, 1e-16);\n                    if (side0 == 0)\n                    {\n                        continue;\n                    }\n                    int side1 = WhichSide(segment_points, this.edge[i].P1, N, 1e-16);\n                    if (side1 == 0)\n                    {\n                        continue;\n                    }\n\n                    if (side0 * side1 < 0)\n                    {\n                        // The projections of this CP and 'c' onto the line P + t * N are on opposite sides of the projection of P.\n                        return false;\n                    }\n                }\n            }\n\n            return true;\n        }\n\n        /// <summary>\n        /// Intersection check between polyhedron and triangle.\n        /// Behaviour for touching objects is undefined.\n        /// </summary>\n        public bool Intersects(Triangle t)\n        {\n            // Using algorithm of separating axes\n\n            // Test faces of triangle for separation.\n            if (WhichSide(this.vertex, t.A, t.Normal) > 0)\n            {\n                // this CP is entirely on the positive side of the line P + t * N\n                return false;\n            }\n            if (WhichSide(this.vertex, t.A, -t.Normal) > 0)\n            {\n                // this CP is entirely on the positive side of the line P + t * N\n                return false;\n            }\n\n            // Test faces of this CP for separation. Because of the counterclockwise ordering,\n            // the projection interval for this CP is (-inf, 0].\n            // Determine whether 't' is on the positive side of the line\n            Point3d[] triangle_points = { t.A, t.B, t.C };\n            for (int i = 0; i < this.numFaces; i++)\n            {\n                if (WhichSide(triangle_points, this.face[i].Vertex[0], this.face[i].normal) > 0)\n                {\n                    // 't' is entirely on the positive side of the line P + t * N\n                    return false;\n                }\n            }\n\n            // Test cross products of edges\n            foreach (Segment3d s1 in ListOfEdges)\n            {\n                Point3d D0 = s1.P2 - s1.P1;\n                for (int j0 = 2, j1 = 0; j1 < 3; j0 = j1++)\n                {\n                    Point3d D1 = triangle_points[j1] - triangle_points[j0];\n                    Point3d N = D0.Cross(D1);\n\n                    if (N.X != 0 || N.Y != 0 || N.Z != 0)\n                    {\n                        int side0 = WhichSide(this.vertex, s1.P1, N, 1e-16);\n                        if (side0 == 0)\n                        {\n                            continue;\n                        }\n                        int side1 = WhichSide(triangle_points, s1.P1, N, 1e-16);\n                        if (side1 == 0)\n                        {\n                            continue;\n                        }\n\n                        if (side0 * side1 < 0)\n                        {\n                            // The projections of this CP and 't' onto the line P + t * N are on opposite sides of the projection of P.\n                            return false;\n                        }\n                    }\n                }\n\n            }\n\n            return true;\n        }\n\n        private int WhichSide(Point3d[] vertex, Vector3d P, Vector3d D, double tolerance = 0)\n        {\n            // The vertices are projected to the form P+t*D.\n            // The return value is:\n            //     +1 - if all t>0\n            //     -1 - if all t<0\n            //      0 - otherwise, in which case the line/plane splits the polygon/polyhedron projection\n\n            int positive = 0, negative = 0;\n\n            for (int i = 0; i < vertex.Length; i++)\n            {\n                // Project vertex onto the line\n                double t = D * (vertex[i].ToVector - P);\n                if (t > tolerance)\n                {\n                    positive++;\n                    if (negative > 0) return 0;\n                }\n                else if (t < -tolerance)\n                {\n                    negative++;\n                    if (positive > 0) return 0;\n                }\n            }\n\n            return positive > 0 ? 1 : -1;\n        }\n\n        private int WhichSide(Point3d[] vertex, Point3d P, Point3d D, double tolerance = 0)\n        {\n            // The vertices are projected to the form P+t*D.\n            // The return value is:\n            //     +1 - if all t>0\n            //     -1 - if all t<0\n            //      0 - otherwise, in which case the line/plane splits the polygon/polyhedron projection\n\n            int positive = 0, negative = 0;\n\n            for (int i = 0; i < vertex.Length; i++)\n            {\n                // Project vertex onto the line\n                double t = D.Dot(vertex[i] - P);\n                if (t > tolerance)\n                {\n                    positive++;\n                    if (negative > 0) return 0;\n                }\n                else if (t < -tolerance)\n                {\n                    negative++;\n                    if (positive > 0) return 0;\n                }\n            }\n\n            return positive > 0 ? 1 : -1;\n        }\n\n        private int WhichSide(Point3d[] vertex, Point3d P, Vector3d D, double tolerance = 0)\n        {\n            // The vertices are projected to the form P+t*D.\n            // The return value is:\n            //     +1 - if all t>0\n            //     -1 - if all t<0\n            //      0 - otherwise, in which case the line/plane splits the polygon/polyhedron projection\n\n            int positive = 0, negative = 0;\n\n            for (int i = 0; i < vertex.Length; i++)\n            {\n                // Project vertex onto the line\n                double t = D.Dot(vertex[i] - P);\n                if (t > tolerance)\n                {\n                    positive++;\n                    if (negative > 0) return 0;\n                }\n                else if (t < -tolerance)\n                {\n                    negative++;\n                    if (positive > 0) return 0;\n                }\n            }\n\n            return positive > 0 ? 1 : -1;\n        }\n\n        private int WhichSide(IVector[] vertex, IVector P, IVector D, double tolerance = 0)\n        {\n            // The vertices are projected to the form P+t*D.\n            // The return value is:\n            //     +1 - if all t>0\n            //     -1 - if all t<0\n            //      0 - otherwise, in which case the line/plane splits the polygon/polyhedron projection\n\n            int positive = 0, negative = 0;\n\n            for (int i = 0; i < vertex.Length; i++)\n            {\n                // Project vertex onto the line\n                double t = D.Dot(vertex[i].Subtract(P));\n                if (t > tolerance)\n                {\n                    positive++;\n                    if (negative > 0) return 0;\n                }\n                else if (t < -tolerance)\n                {\n                    negative++;\n                    if (positive > 0) return 0;\n                }\n            }\n\n            return positive > 0 ? 1 : -1;\n        }\n\n\n        /// <summary>\n        /// Check if polyhedron is located inside box.\n        /// </summary>\n        public bool IsInside(Box3d box)\n        {\n            for (int i = 0; i < this.vertex.Length; i++)\n            {\n                if (!this.vertex[i].IsInside(box)) return false;\n \n            }\n            return true;\n        }\n\n        /// <summary>\n        /// Check if polyhedron intersects box.\n        /// </summary>\n        public bool Intersects(Box3d box)\n        {\n            ConvexPolyhedron cp = ConvexPolyhedron.FromBox(box);\n            return this.Intersects(cp);\n        }\n\n\n        #endregion\n\n\n\n\n        internal override int _PointLocation(Point3d p)\n        {\n            int sum = 0;\n            int product = 1;\n\n            foreach (Face f in face)\n            {\n                int v = _SameSide(f.Vertex[0], f.normal, p);\n                if (v < 0)\n                {\n                    return -1; // Point is outside\n                }\n                sum += v;\n                product *= v;\n            }\n\n            if (sum == face.Length)\n            {\n                return 1; // Point is strictly inside tetrahedron\n            }\n            else\n            {\n                return 0; // Point is on boundary\n            }\n        }\n\n        private int _SameSide(Point3d a, Vector3d normal, Point3d p)\n        {\n            double dot_p = normal * new Vector3d(p, a);\n            if (GeometRi3D.AlmostEqual(dot_p, 0.0))\n            {\n                return 0; // Point is on face\n            }\n            else if (dot_p > 0)\n            {\n                return 1; // point is on the back side for this face\n            }\n            else\n            {\n                return -2;\n            }\n        }\n\n\n        #region \"TranslateRotateReflect\"\n\n        /// <summary>\n        /// Translate polyhedron by a vector\n        /// </summary>\n        public ConvexPolyhedron Translate(Vector3d v)\n        {\n            for (int i = 0; i < vertex.Length; i++)\n            {\n                vertex[i] = vertex[i].Translate(v);\n            }\n\n            _list_e = null;\n            _aabb = null;\n            return this;\n        }\n\n        /// <summary>\n        /// Rotate polyhedron around point 'p' as a rotation center.\n        /// </summary>\n        public ConvexPolyhedron Rotate(Rotation r, Point3d p)\n        {\n            Matrix3d m = r.ToRotationMatrix;\n\n            for (int i = 0; i < vertex.Length; i++)\n            {\n                vertex[i] = m * (vertex[i] - p) + p;\n            }\n\n            for (int i = 0; i < face.Length; i++)\n            {\n                face[i].normal = m * face[i].normal;\n            }\n            _list_e = null;\n            _aabb = null;\n            return this;\n        }\n\n        /// <summary>\n        /// Scale polyhedron relative to center point\n        /// </summary>\n        public ConvexPolyhedron Scale(double scale)\n        {\n            return Scale(scale, this.Center);\n        }\n\n        /// <summary>\n        /// Scale polyhedron relative to given point\n        /// </summary>\n        public ConvexPolyhedron Scale(double scale, Point3d scaling_center)\n        {\n            for (int i = 0; i < vertex.Length; i++)\n            {\n                vertex[i] = scaling_center + scale * (vertex[i] - scaling_center);\n            }\n\n            _list_e = null;\n            _aabb = null;\n            return this;\n        }\n\n        /// <summary>\n        /// Non-uniform scaling of polyhedron relative to given point\n        /// </summary>\n        public virtual ConvexPolyhedron Scale(double scale_x, double scale_y, double scale_z, Point3d scaling_center)\n        {\n            Point3d center = scaling_center;\n            Matrix3d m = Matrix3d.DiagonalMatrix(scale_x, scale_y, scale_z);\n            Matrix3d m_1 = Matrix3d.DiagonalMatrix(1.0 / scale_x, 1.0 / scale_y, 1.0 / scale_z);\n\n            for (int i = 0; i < vertex.Length; i++)\n            {\n                vertex[i] = center.Translate(m * (vertex[i] - center).ToVector); ;\n            }\n\n            for (int i = 0; i < face.Length; i++)\n            {\n                face[i].normal = (Vector3d)(m_1 * face[i].normal).Normalized;\n            }\n            _list_e = null;\n            _aabb = null;\n            return this;\n        }\n\n        /// <summary>\n        /// Non-uniform scaling of polyhedron relative to center point\n        /// </summary>\n        public virtual ConvexPolyhedron Scale(double scale_x, double scale_y, double scale_z)\n        {\n            return Scale(scale_x, scale_y, scale_z, this.Center);\n        }\n\n        #endregion\n\n        /// <summary>\n        /// String representation of an object in global coordinate system.\n        /// </summary>\n        public override string ToString()\n        {\n            return ToString(Coord3d.GlobalCS);\n        }\n\n        /// <summary>\n        /// String representation of an object in global coordinate system.\n        /// </summary>\n        public string ToString(bool full_precision = false)\n        {\n            return ToString(Coord3d.GlobalCS, full_precision);\n        }\n\n        /// <summary>\n        /// String representation of an object in reference coordinate system.\n        /// </summary>\n        public string ToString(Coord3d coord, bool full_precision = false)\n        {\n            string nl = System.Environment.NewLine;\n\n            if (coord == null) { coord = Coord3d.GlobalCS; }\n\n            string str = string.Format(\"Convex polyhedron (reference coord.sys. \") + coord.Name + \"):\" + nl;\n            str += string.Format(\"int numVertices = {0};\", this.numVertices) + nl;\n            str += string.Format(\"int numEdges = {0};\", this.numEdges) + nl;\n            str += string.Format(\"int numFaces = {0};\", this.numFaces) + nl;\n\n            str += string.Format(\"Point3d[] vertices = new Point3d[{0}];\", this.numVertices) + nl;\n            for (int i = 0; i < vertex.Length; i++)\n            {\n                Point3d p = vertex[i].ConvertTo(coord);\n                if (full_precision)\n                {\n                    str += string.Format(\"vertices[{0}] = new Point3d({1}, {2}, {3});\", i, p.X, p.Y, p.Z) + nl;\n                }\n                else\n                {\n                    str += string.Format(\"vertices[{0}] = new Point3d({1,10:g5}, {2,10:g5}, {3,10:g5});\", i, p.X, p.Y, p.Z) + nl;\n                }\n            }\n\n            str += string.Format(\"ConvexPolyhedron.Edge[] edges = new ConvexPolyhedron.Edge[{0}];\", this.numEdges) + nl;\n            for (int i = 0; i < edge.Length; i++)\n            {\n                str += string.Format(\"edges[{0}] = new ConvexPolyhedron.Edge({1}, {2});\", i, edge[i].p1, edge[i].p2) + nl;\n            }\n\n            str += string.Format(\"ConvexPolyhedron.Face[] faces = new ConvexPolyhedron.Face[{0}];\", this.numFaces) + nl;\n            for (int i = 0; i < face.Length; i++)\n            {\n                str += string.Format(\"faces[{0}] = new ConvexPolyhedron.Face({1}, new int[] {{ {2}\", i, face[i].numVertices, face[i].vertex[0]);\n                for (int j = 1; j < face[i].numVertices; j++)\n                {\n                    str += string.Format(\", {0}\", face[i].vertex[j]);\n                }\n                str += string.Format(\" }});\") + nl;\n            }\n\n            str += string.Format(\"ConvexPolyhedron cp = new ConvexPolyhedron(numVertices, numEdges, numFaces, vertices, edges, faces, true);\") + nl;\n\n            return str;\n        }\n\n\n    }\n}\n"
  },
  {
    "path": "GeometRi/Coord3D.cs",
    "content": "﻿using System;\nusing static System.Math;\n\nnamespace GeometRi\n{\n    /// <summary>\n    /// Cartesian coordinate system defined by origin and transformation matrix (in row format).\n    /// </summary>\n#if NET20_OR_GREATER\n    [Serializable]\n#endif\n    public class Coord3d\n    {\n\n        private Point3d _origin;\n        private Matrix3d _axes;\n        private string _name;\n        private static int count = 0;\n\n        public static readonly Coord3d GlobalCS = new Coord3d(\"Global_CS\");\n\n#region \"Constructors\"\n        /// <summary>\n        /// Initializes default coordinate system.\n        /// </summary>\n        /// <param name=\"name\">Name of the coordinate system.</param>\n        public Coord3d(string name = \"\")\n        {\n            _origin = new Point3d(0, 0, 0);\n            _axes = Matrix3d.Identity();\n            if ((!string.IsNullOrEmpty(name)))\n            {\n                _name = name;\n            }\n            else\n            {\n                _name = \"Coord \" + count.ToString();\n            }\n            count += 1;\n        }\n\n        /// <summary>\n        /// Initializes coordinate system using origin point  and transformation matrix.\n        /// </summary>\n        /// <param name=\"p\">Origin of the coordinate system.</param>\n        /// <param name=\"m\">Transformation matrix (in row format).</param>\n        /// <param name=\"name\">Name of the coordinate system.</param>\n        public Coord3d(Point3d p, Matrix3d m, string name = \"\")\n        {\n            if (!m.IsOrthogonal)\n            {\n                throw new ArgumentException(\"The matrix is not orthogonal\");\n            }\n\n            _origin = p.ConvertToGlobal();\n            _axes = m.Copy();\n            if ((!string.IsNullOrEmpty(name)))\n            {\n                _name = name;\n            }\n            else\n            {\n                _name = \"Coord \" + count.ToString();\n            }\n            count += 1;\n        }\n\n        /// <summary>\n        /// Initializes coordinate system using origin point and two vectors.\n        /// </summary>\n        /// <param name=\"p\">Origin of the coordinate system.</param>\n        /// <param name=\"v1\">Vector oriented along the X axis.</param>\n        /// <param name=\"v2\">Vector in the XY plane.</param>\n        /// <param name=\"name\">Name of the coordinate system.</param>\n        public Coord3d(Point3d p, Vector3d v1, Vector3d v2, string name = \"\")\n        {\n\n            if (v1.IsParallelTo(v2))\n            {\n                throw new Exception(\"Vectors are parallel\");\n            }\n\n            v1 = v1.ConvertToGlobal().Normalized;\n            Vector3d v3 = v1.Cross(v2).Normalized;\n            v2 = v3.Cross(v1).Normalized;\n\n            _origin = p.ConvertToGlobal();\n            _axes = new Matrix3d(v1, v2, v3);\n            if ((!string.IsNullOrEmpty(name)))\n            {\n                _name = name;\n            }\n            else\n            {\n                _name = \"Coord \" + count.ToString();\n            }\n            count += 1;\n        }\n\n        /// <summary>\n        /// Initializes coordinate system using three points.\n        /// </summary>\n        /// <param name=\"p1\">Origin of the coordinate system.</param>\n        /// <param name=\"p2\">Point on the X axis.</param>\n        /// <param name=\"p3\">Point on the XY plane.</param>\n        /// <param name=\"name\">Name of the coordinate system.</param>\n        public Coord3d(Point3d p1, Point3d p2, Point3d p3, string name = \"\")\n        {\n            Vector3d v1 = new Vector3d(p1, p2);\n            Vector3d v2 = new Vector3d(p1, p3);\n\n            if (v1.IsParallelTo(v2))\n            {\n                throw new Exception(\"Points are collinear\");\n            }\n\n            v1 = v1.ConvertToGlobal().Normalized;\n            Vector3d v3 = v1.Cross(v2).Normalized;\n            v2 = v3.Cross(v1).Normalized;\n\n            _origin = p1.ConvertToGlobal();\n            _axes = new Matrix3d(v1, v2, v3);\n            if ((!string.IsNullOrEmpty(name)))\n            {\n                _name = name;\n            }\n            else\n            {\n                _name = \"Coord \" + count.ToString();\n            }\n            count += 1;\n        }\n\n        /// <summary>\n        /// Initializes coordinate system using origin point and two double arrays.\n        /// </summary>\n        /// <param name=\"p\">Origin of the coordinate system.</param>\n        /// <param name=\"d1\">Vector oriented along the X axis.</param>\n        /// <param name=\"d2\">Vector in the XY plane.</param>\n        /// <param name=\"name\">Name of the coordinate system.</param>\n        public Coord3d(Point3d p, double[] d1, double[] d2, string name = \"\")\n        {\n            Vector3d v1 = new Vector3d(d1);\n            Vector3d v2 = new Vector3d(d2);\n            if (v1.IsParallelTo(v2))\n            {\n                throw new Exception(\"Vectors are parallel\");\n            }\n\n            v1 = v1.Normalized;\n            Vector3d v3 = v1.Cross(v2).Normalized;\n            v2 = v3.Cross(v1).Normalized;\n\n            _origin = p.ConvertToGlobal();\n            _axes = new Matrix3d(v1, v2, v3);\n            if ((!string.IsNullOrEmpty(name)))\n            {\n                _name = name;\n            }\n            else\n            {\n                _name = \"Coord \" + count.ToString();\n            }\n            count += 1;\n        }\n        #endregion\n\n        /// <summary>\n        /// Creates copy of the object\n        /// </summary>\n        public Coord3d Copy()\n        {\n            return new Coord3d(_origin, _axes);\n        }\n\n\n        /// <summary>\n        /// Get or Set the origin of the coordinate system\n        /// </summary>\n        /// <returns></returns>\n        public Point3d Origin\n        {\n            get { return _origin; }\n            set { _origin = value.ConvertToGlobal(); }\n        }\n        /// <summary>\n        /// Get or Set unit vectors of the axes, stored as row-matrix(3x3)\n        /// </summary>\n        /// <returns></returns>\n        public Matrix3d Axes\n        {\n            get { return _axes; }\n            set\n            {\n                if (value.IsOrthogonal)\n                {\n                    _axes = value.Copy();\n                }\n                else\n                {\n                    throw new ArgumentException(\"The matrix is not orthogonal\");\n                }\n            }\n        }\n\n        public string Name\n        {\n            get { return _name; }\n        }\n\n        /// <summary>\n        /// Get total number of defined coordinate systems\n        /// </summary>\n        public static int Counts\n        {\n            get { return count; }\n        }\n\n\n        /// <summary>\n        /// Get X-axis\n        /// </summary>\n        public Vector3d Xaxis\n        {\n            get { return _axes.Row1; }\n        }\n        /// <summary>\n        /// Get Y-axis\n        /// </summary>\n        public Vector3d Yaxis\n        {\n            get { return _axes.Row2; }\n        }\n        /// <summary>\n        /// Get Z-axis\n        /// </summary>\n        public Vector3d Zaxis\n        {\n            get { return _axes.Row3; }\n        }\n\n        /// <summary>\n        /// XY plane in the current coordinate system\n        /// </summary>\n        public Plane3d XY_plane\n        {\n            get { return new Plane3d(0, 0, 1, 0, this); }\n        }\n\n        /// <summary>\n        /// XZ plane in the current coordinate system\n        /// </summary>\n        public Plane3d XZ_plane\n        {\n            get { return new Plane3d(0, 1, 0, 0, this); }\n        }\n\n        /// <summary>\n        /// YZ plane in the current coordinate system\n        /// </summary>\n        public Plane3d YZ_plane\n        {\n            get { return new Plane3d(1, 0, 0, 0, this); }\n        }\n\n        /// <summary>\n        /// Rotate coordinate system\n        /// </summary>\n        public void Rotate(Rotation r)\n        {\n            _axes = _axes * r.ConvertToGlobal().ToRotationMatrix.Transpose();\n        }\n\n        /// <summary>\n        /// Rotate coordinate system around rotation axis\n        /// </summary>\n        /// <param name=\"axis\">Rotation axis</param>\n        /// <param name=\"angle\">Rotation angle (radians, counterclockwise)</param>\n        public void Rotate(Vector3d axis, double angle)\n        {\n            _axes = _axes * Matrix3d.RotationMatrix(axis.ConvertToGlobal(), angle).Transpose();\n        }\n\n        /// <summary>\n        /// Rotate coordinate system around rotation axis\n        /// </summary>\n        /// <param name=\"axis\">Rotation axis</param>\n        /// <param name=\"angle\">Rotation angle (degrees, counterclockwise)</param>\n        public void RotateDeg(Vector3d axis, double angle)\n        {\n            _axes = _axes * Matrix3d.RotationMatrix(axis.ConvertToGlobal(), angle * PI / 180).Transpose();\n        }\n\n        /// <summary>\n        /// Determines whether two coordinate systems are equal.\n        /// <para>Object's references are compared for speed.</para>\n        /// </summary>\n        public override bool Equals(object obj)\n        {\n            return object.ReferenceEquals(this, obj);\n        }\n\n        /// <summary>\n        /// Returns the hashcode for the object.\n        /// </summary>\n        public override int GetHashCode()\n        {\n            return _name.GetHashCode();\n        }\n\n        /// <summary>\n        /// String representation of an object in global coordinate system.\n        /// </summary>\n        public override String ToString()\n        {\n            System.Text.StringBuilder str = new System.Text.StringBuilder();\n            string nl = System.Environment.NewLine;\n            str.Append(\"Coord3d: \" + _name + nl);\n            str.Append(string.Format(\"Origin -> X: {0,10:g5}, Y: {1,10:g5}, Z: {2,10:g5}\", _origin.X, _origin.Y, _origin.Z) + nl);\n            str.Append(string.Format(\"Xaxis  -> ({0,10:g5}, {1,10:g5}, {2,10:g5})\", Xaxis.X, Xaxis.Y, Xaxis.Z) + nl);\n            str.Append(string.Format(\"Yaxis  -> ({0,10:g5}, {1,10:g5}, {2,10:g5})\", Yaxis.X, Yaxis.Y, Yaxis.Z) + nl);\n            str.Append(string.Format(\"Zaxis  -> ({0,10:g5}, {1,10:g5}, {2,10:g5})\", Zaxis.X, Zaxis.Y, Zaxis.Z));\n            return str.ToString();\n        }\n\n        // Operators overloads\n        //-----------------------------------------------------------------\n     /*   public static bool operator ==(Coord3d c1, Coord3d c2)\n        {\n\n            if ((object)c1 != null)\n            {\n                return c1.Equals(c2);\n            }\n            else if ((object)c1 == null && (object)c2 == null)\n            {\n                return true;\n            }\n            else\n            {\n                return false;\n            }\n        }\n        public static bool operator !=(Coord3d c1, Coord3d c2)\n        {\n            if ((object)c1 != null)\n            {\n                return !c1.Equals(c2);\n            }\n            else if ((object)c1 == null && (object)c2 == null)\n            {\n                return false;\n            }\n            else\n            {\n                return true;\n            }\n        }\n     */\n\n    }\n}\n\n\n\n"
  },
  {
    "path": "GeometRi/Ellipse.cs",
    "content": "﻿using System;\nusing static System.Math;\n\nnamespace GeometRi\n{\n    /// <summary>\n    /// Ellipse in 3D space, defined by center point and two orthogonal vectors, major and minor semiaxes.\n    /// </summary>\n#if NET20_OR_GREATER\n    [Serializable]\n#endif\n    public class Ellipse : FiniteObject, IPlanarObject, IFiniteObject\n    {\n\n        private Point3d _point;\n        private Vector3d _v1;\n        private Vector3d _v2;\n\n        /// <summary>\n        /// Initializes ellipse instance using center point and two orthogonal vectors.\n        /// </summary>\n        /// <param name=\"Center\">Center point.</param>\n        /// <param name=\"v1\">First semiaxis.</param>\n        /// <param name=\"v2\">Second semiaxis.</param>\n        public Ellipse(Point3d Center, Vector3d v1, Vector3d v2)\n        {\n            if (!v1.IsOrthogonalTo(v2))\n            {\n                throw new Exception(\"Semiaxes are not orthogonal\");\n            }\n            _point = Center.Copy();\n            if (v1.Norm >= v2.Norm)\n            {\n                _v1 = v1.Copy();\n                _v2 = v2.Copy();\n            }\n            else\n            {\n                _v1 = v2.Copy();\n                _v2 = v1.Copy();\n            }\n\n        }\n\n        /// <summary>\n        /// Creates copy of the object\n        /// </summary>\n        public Ellipse Copy()\n        {\n            return new Ellipse(_point.Copy(), _v1.Copy(), _v2.Copy());\n        }\n\n        #region \"Properties\"\n        public Point3d Center\n        {\n            get { return _point; }\n        }\n\n        public Vector3d MajorSemiaxis\n        {\n            get { return _v1; }\n        }\n\n        public Vector3d MinorSemiaxis\n        {\n            get { return _v2; }\n        }\n\n        public Vector3d Normal\n        {\n            get { return _v1.Cross(_v2).Normalized; }\n        }\n\n        public bool IsOriented\n        {\n            get { return false; }\n        }\n\n        /// <summary>\n        /// Length of the major semiaxis\n        /// </summary>\n        public double A\n        {\n            get { return _v1.Norm; }\n        }\n\n        /// <summary>\n        /// Length of the minor semiaxis\n        /// </summary>\n        public double B\n        {\n            get { return _v2.Norm; }\n        }\n\n        /// <summary>\n        /// Distance from center to focus\n        /// </summary>\n        public double F\n        {\n            get { return Sqrt(_v1.NormSquared - _v2.NormSquared); }\n        }\n\n        /// <summary>\n        /// First focus\n        /// </summary>\n        public Point3d F1\n        {\n            get { return _point.Translate(F * _v1.Normalized); }\n        }\n\n        /// <summary>\n        /// Second focus\n        /// </summary>\n        public Point3d F2\n        {\n            get { return _point.Translate(-F * _v1.Normalized); }\n        }\n\n        /// <summary>\n        /// Eccentricity of the ellipse\n        /// </summary>\n        public double E\n        {\n            get { return Sqrt(1 - _v2.NormSquared / _v1.NormSquared); }\n        }\n\n        public double Area\n        {\n            get { return PI * A * B; }\n        }\n\n        /// <summary>\n        /// Approximate circumference of the ellipse\n        /// </summary>\n        public double Perimeter\n        {\n            get\n            {\n                double a = _v1.Norm;\n                double b = _v2.Norm;\n                double h = Math.Pow((a - b), 2) / Math.Pow((a + b), 2);\n                return PI * (a + b) * (1 + 3 * h / (10 + Sqrt(4 - 3 * h)));\n            }\n        }\n\n        /// <summary>\n        /// Convert ellipse to plane object.\n        /// </summary>\n        public Plane3d ToPlane\n        {\n            get\n            {\n                return new Plane3d(_point, Normal);\n            }\n        }\n        #endregion\n\n        #region \"ParallelMethods\"\n        /// <summary>\n        /// Check if two objects are parallel\n        /// </summary>\n        public bool IsParallelTo(ILinearObject obj)\n        {\n            return this.Normal.IsOrthogonalTo(obj.Direction);\n        }\n\n        /// <summary>\n        /// Check if two objects are NOT parallel\n        /// </summary>\n        public bool IsNotParallelTo(ILinearObject obj)\n        {\n            return !this.Normal.IsOrthogonalTo(obj.Direction);\n        }\n\n        /// <summary>\n        /// Check if two objects are orthogonal\n        /// </summary>\n        public bool IsOrthogonalTo(ILinearObject obj)\n        {\n            return this.Normal.IsParallelTo(obj.Direction);\n        }\n\n        /// <summary>\n        /// Check if two objects are parallel\n        /// </summary>\n        public bool IsParallelTo(IPlanarObject obj)\n        {\n            return this.Normal.IsParallelTo(obj.Normal);\n        }\n\n        /// <summary>\n        /// Check if two objects are NOT parallel\n        /// </summary>\n        public bool IsNotParallelTo(IPlanarObject obj)\n        {\n            return this.Normal.IsNotParallelTo(obj.Normal);\n        }\n\n        /// <summary>\n        /// Check if two objects are orthogonal\n        /// </summary>\n        public bool IsOrthogonalTo(IPlanarObject obj)\n        {\n            return this.Normal.IsOrthogonalTo(obj.Normal);\n        }\n\n        /// <summary>\n        /// Check if two objects are coplanar\n        /// </summary>\n        public bool IsCoplanarTo(IPlanarObject obj)\n        {\n            return GeometRi3D._coplanar(this, obj);\n        }\n\n        /// <summary>\n        /// Check if two objects are coplanar\n        /// </summary>\n        public bool IsCoplanarTo(ILinearObject obj)\n        {\n            return GeometRi3D._coplanar(this, obj);\n        }\n        #endregion\n\n        #region \"BoundingBox\"\n        /// <summary>\n        /// Return minimum bounding box.\n        /// </summary>\n        public Box3d MinimumBoundingBox\n        {\n            get\n            {\n                Vector3d v1 = _v1.Normalized;\n                Vector3d v2 = _v2.Normalized;\n                Vector3d v3 = v1.Cross(v2).Normalized;\n                Matrix3d m = new Matrix3d(v1, v2, v3);\n                Rotation r = new Rotation(m.Transpose());\n                return new Box3d(_point, 2.0 * this.A, 2.0 * this.B, 0, r);\n            }\n        }\n\n        /// <summary>\n        /// Return Bounding Box in given coordinate system.\n        /// </summary>\n        public Box3d BoundingBox(Coord3d coord = null)\n        {\n            coord = (coord == null) ? Coord3d.GlobalCS : coord;\n            Line3d l1 = new Line3d(coord.Origin, coord.Xaxis);\n            Line3d l2 = new Line3d(coord.Origin, coord.Yaxis);\n            Line3d l3 = new Line3d(coord.Origin, coord.Zaxis);\n            Segment3d s1 = this.ProjectionTo(l1);\n            Segment3d s2 = this.ProjectionTo(l2);\n            Segment3d s3 = this.ProjectionTo(l3);\n            return new Box3d(_point, s1.Length, s2.Length, s3.Length, coord);\n        }\n\n        /// <summary>\n        /// Return Axis Aligned Bounding Box (AABB).\n        /// </summary>\n        public AABB AABB()\n        {\n            Line3d l1 = new Line3d(_point, Coord3d.GlobalCS.Xaxis);\n            Line3d l2 = new Line3d(_point, Coord3d.GlobalCS.Yaxis);\n            Line3d l3 = new Line3d(_point, Coord3d.GlobalCS.Zaxis);\n            Segment3d s1 = this.ProjectionTo(l1);\n            Segment3d s2 = this.ProjectionTo(l2);\n            Segment3d s3 = this.ProjectionTo(l3);\n            return new AABB(_point, s1.Length, s2.Length, s3.Length);\n        }\n\n        /// <summary>\n        /// Return bounding sphere.\n        /// </summary>\n        public Sphere BoundingSphere\n        {\n            get { return new Sphere(_point, this.A); }\n\n        }\n        #endregion\n\n        /// <summary>\n        /// Returns point on ellipse for given parameter 't' (0 &lt;= t &lt; 2Pi)\n        /// </summary>\n        public Point3d ParametricForm(double t)\n        {\n\n            return _point + _v1.ToPoint * Cos(t) + _v2.ToPoint * Sin(t);\n\n        }\n\n        /// <summary>\n        /// Orthogonal projection of ellipse to line.\n        /// </summary>\n        public Segment3d ProjectionTo(Line3d l)\n        {\n            // Using algorithm for ellipsoid with third semiaxis -> 0\n            // Stephen B. Pope \"Algorithms for Ellipsoids\"\n            // https://tcg.mae.cornell.edu/pubs/Pope_FDA_08.pdf\n\n            Coord3d lc = new Coord3d(_point, _v1, _v2);\n            Point3d x0 = l.Point.ConvertTo(lc);\n            Vector3d v = l.Direction.ConvertTo(lc);\n\n            Matrix3d L_T = Matrix3d.DiagonalMatrix(this.A, this.B, 0);\n            Vector3d c = new Vector3d(0.0, 0.0, 0.0, lc);\n            double s0 = v * (c - x0.ToVector) / (v * v);\n            Vector3d w = L_T * v / (v * v);\n            Point3d P1 = x0.Translate((s0 + w.Norm) * v);\n            Point3d P2 = x0.Translate((s0 - w.Norm) * v);\n            return new Segment3d(P1, P2);\n        }\n\n        /// <summary>\n        /// Orthogonal projection of the ellipse to plane\n        /// </summary>\n        public Ellipse ProjectionTo(Plane3d s)\n        {\n\n            Point3d c = _point.ProjectionTo(s);\n            Point3d q = _point.Translate(_v1).ProjectionTo(s);\n            Point3d p = _point.Translate(_v2).ProjectionTo(s);\n\n            Vector3d f1 = new Vector3d(c, p);\n            Vector3d f2 = new Vector3d(c, q);\n\n            double t0 = 0.5 * Atan2(2 * f1 * f2, f1 * f1 - f2 * f2);\n            Vector3d v1 = f1 * Cos(t0) + f2 * Sin(t0);\n            Vector3d v2 = f1 * Cos(t0 + PI / 2) + f2 * Sin(t0 + PI / 2);\n\n            return new Ellipse(c, v1, v2);\n        }\n\n        /// <summary>\n        /// Intersection of ellipse with line.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'.\n        /// </summary>\n        public object IntersectionWith(Line3d l)\n        {\n\n            // Relative tolerance ================================\n            if (!GeometRi3D.UseAbsoluteTolerance)\n            {\n                double tol = GeometRi3D.Tolerance;\n                GeometRi3D.Tolerance = tol * this.A;\n                GeometRi3D.UseAbsoluteTolerance = true;\n                object result = this.IntersectionWith(l);\n                GeometRi3D.UseAbsoluteTolerance = false;\n                GeometRi3D.Tolerance = tol;\n                return result;\n            }\n            //====================================================\n\n\n            if (l.Direction.IsOrthogonalTo(this.Normal))\n            {\n                if (l.Point.BelongsTo(new Plane3d(this.Center, this.Normal)))\n                {\n                    // coplanar objects\n                    // Find intersection of line and ellipse (2D)\n                    // Solution from: https://www.ambrbit.com/TrigoCalc/Circles2/Ellipse/EllipseLine.htm\n\n                    Coord3d local_coord = new Coord3d(this.Center, this._v1, this._v2);\n                    Point3d p = l.Point.ConvertTo(local_coord);\n                    Vector3d v = l.Direction.ConvertTo(local_coord);\n                    double a = this.A;\n                    double b = this.B;\n\n                    if (Abs(v.Y / v.X) > 100)\n                    {\n                        // line is almost vertical, rotate local coord\n                        local_coord = new Coord3d(this.Center, this._v2, this._v1);\n                        p = l.Point.ConvertTo(local_coord);\n                        v = l.Direction.ConvertTo(local_coord);\n                        a = this.B;\n                        b = this.A;\n                    }\n\n                    // Line equation in form: y = mx + c\n                    double m = v.Y / v.X;\n                    double c = p.Y - m * p.X;\n\n                    double amb = Math.Pow(a, 2) * Math.Pow(m, 2) + Math.Pow(b, 2);\n                    double det = amb - Math.Pow(c, 2);\n                    if (det < -GeometRi3D.Tolerance)\n                    {\n                        return null;\n                    }\n                    else if (det > 1e-12)\n                    {\n                        double x1 = (-Math.Pow(a, 2) * m * c + a * b * Sqrt(det)) / amb;\n                        double x2 = (-Math.Pow(a, 2) * m * c - a * b * Sqrt(det)) / amb;\n                        double y1 = (Math.Pow(b, 2) * c + a * b * m * Sqrt(det)) / amb;\n                        double y2 = (Math.Pow(b, 2) * c - a * b * m * Sqrt(det)) / amb;\n                        return new Segment3d(new Point3d(x1, y1, 0, local_coord), new Point3d(x2, y2, 0, local_coord));\n                    }\n                    else\n                    {\n                        double x = -Math.Pow(a, 2) * m * c / amb;\n                        double y = Math.Pow(b, 2) * c / amb;\n                        return new Point3d(x, y, 0, local_coord);\n                    }\n\n                }\n                else\n                {\n                    // parallel objects\n                    return null;\n                }\n            }\n            else\n            {\n                // Line intersects ellipse' plane\n                Point3d p = (Point3d)l.IntersectionWith(new Plane3d(this.Center, this.Normal));\n                if (p.BelongsTo(this))\n                {\n                    return p;\n                }\n                else\n                {\n                    return null;\n                }\n            }\n        }\n\n        /// <summary>\n        /// Intersection of ellipse with plane.\n        /// Returns 'null' (no intersection) or object of type 'Ellipse', 'Point3d' or 'Segment3d'.\n        /// </summary>\n        public object IntersectionWith(Plane3d s)\n        {\n\n            // Relative tolerance ================================\n            if (!GeometRi3D.UseAbsoluteTolerance)\n            {\n                double tol = GeometRi3D.Tolerance;\n                GeometRi3D.Tolerance = tol * this.A;\n                GeometRi3D.UseAbsoluteTolerance = true;\n                object result = this.IntersectionWith(s);\n                GeometRi3D.UseAbsoluteTolerance = false;\n                GeometRi3D.Tolerance = tol;\n                return result;\n            }\n            //====================================================\n\n            if (this.Normal.IsParallelTo(s.Normal))\n            {\n                if (this.Center.BelongsTo(s))\n                {\n                    // coplanar objects\n                    return this.Copy();\n                }\n                else\n                {\n                    // parallel objects\n                    return null;\n                }\n            }\n            else\n            {\n                Line3d l = (Line3d)s.IntersectionWith(new Plane3d(this.Center, this.Normal));\n                return this.IntersectionWith(l);\n            }\n\n        }\n\n        /// <summary>\n        /// Intersection of ellipse with segment.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'.\n        /// </summary>\n        public object IntersectionWith(Segment3d s)\n        {\n\n            // Relative tolerance ================================\n            if (!GeometRi3D.UseAbsoluteTolerance)\n            {\n                double tol = GeometRi3D.Tolerance;\n                GeometRi3D.Tolerance = tol * this.A;\n                GeometRi3D.UseAbsoluteTolerance = true;\n                object result = this.IntersectionWith(s);\n                GeometRi3D.UseAbsoluteTolerance = false;\n                GeometRi3D.Tolerance = tol;\n                return result;\n            }\n            //====================================================\n\n            object obj = this.IntersectionWith(s.Line);\n\n            if (obj == null)\n            {\n                return null;\n            }\n            else if (obj.GetType() == typeof(Point3d))\n            {\n                Point3d p = (Point3d)obj;\n                if (p.BelongsTo(s))\n                {\n                    return p;\n                }\n                else\n                {\n                    return null;\n                }\n            }\n            else\n            {\n                return s.IntersectionWith((Segment3d)obj);\n            }\n        }\n\n        /// <summary>\n        /// Intersection of ellipse with ray.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'.\n        /// </summary>\n        public object IntersectionWith(Ray3d r)\n        {\n\n            // Relative tolerance ================================\n            if (!GeometRi3D.UseAbsoluteTolerance)\n            {\n                double tol = GeometRi3D.Tolerance;\n                GeometRi3D.Tolerance = tol * this.A;\n                GeometRi3D.UseAbsoluteTolerance = true;\n                object result = this.IntersectionWith(r);\n                GeometRi3D.UseAbsoluteTolerance = false;\n                GeometRi3D.Tolerance = tol;\n                return result;\n            }\n            //====================================================\n\n            object obj = this.IntersectionWith(r.ToLine);\n\n            if (obj == null)\n            {\n                return null;\n            }\n            else if (obj.GetType() == typeof(Point3d))\n            {\n                Point3d p = (Point3d)obj;\n                if (p.BelongsTo(r))\n                {\n                    return p;\n                }\n                else\n                {\n                    return null;\n                }\n            }\n            else\n            {\n                return r.IntersectionWith((Segment3d)obj);\n            }\n        }\n\n        internal override int _PointLocation(Point3d p)\n        {\n            if (GeometRi3D.UseAbsoluteTolerance)\n            {\n                Plane3d s = new Plane3d(this.Center, this.Normal);\n                Point3d proj = p.ProjectionTo(s);\n                if (GeometRi3D.AlmostEqual(p.DistanceTo(proj), 0))\n                {\n                    if (GeometRi3D.AlmostEqual(p.DistanceTo(this.ClosestPoint(proj)), 0))\n                    {\n                        return 0; // Point is on boundary\n                    }\n                    else if (GeometRi3D.Smaller(proj.DistanceTo(this.F1) + proj.DistanceTo(this.F2), 2 * this.A))\n                    {\n                        return 1; // Point is strictly inside\n                    }\n                    else\n                    {\n                        return -1; // Point is outside\n                    }\n                }\n                else\n                {\n                    return -1; // Point is outside\n                }\n            }\n            else\n            {\n                double tol = GeometRi3D.Tolerance;\n                GeometRi3D.Tolerance = tol * this.A;\n                GeometRi3D.UseAbsoluteTolerance = true;\n                int result = this._PointLocation(p);\n                GeometRi3D.UseAbsoluteTolerance = false;\n                GeometRi3D.Tolerance = tol;\n                return result;\n            }\n        }\n\n        /// <summary>\n        /// Calculates the point on the ellipse's boundary closest to given point.\n        /// </summary>\n        public Point3d ClosestPoint(Point3d p)\n        {\n\n            // Algorithm by Dr. Robert Nurnberg\n            // http://wwwf.imperial.ac.uk/~rn/distance2ellipse.pdf\n            // Does not work for interior points\n\n            Coord3d local_coord = new Coord3d(this.Center, this._v1, this._v2);\n            p = p.ConvertTo(local_coord);\n\n            if (GeometRi3D.AlmostEqual(p.X, 0) && GeometRi3D.AlmostEqual(p.Y, 0))\n            {\n                // Center point, choose any minor-axis\n                return new Point3d(0, this.B, 0, local_coord);\n            }\n\n            double theta = Atan2(this.A * p.Y, this.B * p.X);\n            int iter = 0;\n            int max_iter = 100;\n            Point3d n0 = p.Copy();\n\n            while (iter < max_iter)\n            {\n                iter += 1;\n                double f = (A * A - B * B) * Cos(theta) * Sin(theta) - p.X * A * Sin(theta) + p.Y * B * Cos(theta);\n                double f_prim = (A * A - B * B) * (Cos(theta) * Cos(theta) - Sin(theta) * Sin(theta))\n                                - p.X * A * Cos(theta) - p.Y * B * Sin(theta);\n                theta = theta - f / f_prim;\n                Point3d n = new Point3d(A * Cos(theta), B * Sin(theta), 0, local_coord);\n\n                if (n0.DistanceTo(n) < GeometRi3D.Tolerance)\n                {\n                    return n;\n                }\n                n0 = n.Copy();\n            }\n\n            return n0;\n        }\n\n        #region \"AngleTo\"\n        /// <summary>\n        /// Angle between two objects in radians (0 &lt; angle &lt; Pi)\n        /// </summary>\n        public double AngleTo(ILinearObject obj)\n        {\n            return GeometRi3D.GetAngle(this, obj);\n        }\n        /// <summary>\n        /// Angle between two objects in degrees (0 &lt; angle &lt; 180)\n        /// </summary>\n        public double AngleToDeg(ILinearObject obj)\n        {\n            return AngleTo(obj) * 180 / PI;\n        }\n\n        /// <summary>\n        /// Angle between two objects in radians (0 &lt; angle &lt; Pi)\n        /// </summary>\n        public double AngleTo(IPlanarObject obj)\n        {\n            return GeometRi3D.GetAngle(this, obj);\n        }\n        /// <summary>\n        /// Angle between two objects in degrees (0 &lt; angle &lt; 180)\n        /// </summary>\n        public double AngleToDeg(IPlanarObject obj)\n        {\n            return AngleTo(obj) * 180 / PI;\n        }\n        #endregion\n\n        #region \"TranslateRotateReflect\"\n        /// <summary>\n        /// Translate ellipse by a vector\n        /// </summary>\n        public Ellipse Translate(Vector3d v)\n        {\n            return new Ellipse(this.Center.Translate(v), _v1, _v2);\n        }\n\n        /// <summary>\n        /// Rotate ellipse by a given rotation matrix\n        /// </summary>\n        [System.Obsolete(\"use Rotation object and specify rotation center: this.Rotate(Rotation r, Point3d p)\")]\n        public Ellipse Rotate(Matrix3d m)\n        {\n            return new Ellipse(this.Center.Rotate(m), _v1.Rotate(m), _v2.Rotate(m));\n        }\n\n        /// <summary>\n        /// Rotate ellipse by a given rotation matrix around point 'p' as a rotation center\n        /// </summary>\n        [System.Obsolete(\"use Rotation object: this.Rotate(Rotation r, Point3d p)\")]\n        public Ellipse Rotate(Matrix3d m, Point3d p)\n        {\n            return new Ellipse(this.Center.Rotate(m, p), _v1.Rotate(m), _v2.Rotate(m));\n        }\n\n        /// <summary>\n        /// Rotate ellipse around point 'p' as a rotation center.\n        /// </summary>\n        public Ellipse Rotate(Rotation r, Point3d p)\n        {\n            return new Ellipse(this.Center.Rotate(r, p), _v1.Rotate(r), _v2.Rotate(r));\n        }\n\n        /// <summary>\n        /// Reflect ellipse in given point\n        /// </summary>\n        public Ellipse ReflectIn(Point3d p)\n        {\n            return new Ellipse(this.Center.ReflectIn(p), _v1.ReflectIn(p), _v2.ReflectIn(p));\n        }\n\n        /// <summary>\n        /// Reflect ellipse in given line\n        /// </summary>\n        public Ellipse ReflectIn(Line3d l)\n        {\n            return new Ellipse(this.Center.ReflectIn(l), _v1.ReflectIn(l), _v2.ReflectIn(l));\n        }\n\n        /// <summary>\n        /// Reflect ellipse in given plane\n        /// </summary>\n        public Ellipse ReflectIn(Plane3d s)\n        {\n            return new Ellipse(this.Center.ReflectIn(s), _v1.ReflectIn(s), _v2.ReflectIn(s));\n        }\n\n        /// <summary>\n        /// Scale ellipse relative to given point\n        /// </summary>\n        public virtual Ellipse Scale(double scale, Point3d scaling_center)\n        {\n            Point3d new_center = scaling_center + scale * (this.Center - scaling_center);\n            return new Ellipse(new_center, _v1 * scale, _v2 * scale);\n        }\n        #endregion\n\n        /// <summary>\n        /// Determines whether two objects are equal.\n        /// </summary>\n        public override bool Equals(object obj)\n        {\n            if (obj == null || (!object.ReferenceEquals(this.GetType(), obj.GetType())))\n            {\n                return false;\n            }\n            Ellipse e = (Ellipse)obj;\n\n            if (GeometRi3D.UseAbsoluteTolerance)\n            {\n                if (GeometRi3D.AlmostEqual(this.A, this.B))\n                {\n                    // Ellipse is circle\n                    if (GeometRi3D.AlmostEqual(e.A, e.B))\n                    {\n                        // Second ellipse also circle\n                        return this.Center == e.Center && GeometRi3D.AlmostEqual(this.A, e.A) && e.Normal.IsParallelTo(this.Normal);\n                    }\n                    else\n                    {\n                        return false;\n                    }\n                }\n                else\n                {\n                    return this.Center == e.Center && GeometRi3D.AlmostEqual(this.A, e.A) && GeometRi3D.AlmostEqual(this.B, e.B) &&\n                           e.MajorSemiaxis.IsParallelTo(this.MajorSemiaxis) && e.MinorSemiaxis.IsParallelTo(this.MinorSemiaxis);\n                }\n            }\n            else\n            {\n                double tol = GeometRi3D.Tolerance;\n                GeometRi3D.Tolerance = tol * e.MajorSemiaxis.Norm;\n                GeometRi3D.UseAbsoluteTolerance = true;\n\n                if (GeometRi3D.AlmostEqual(this.A, this.B))\n                {\n                    // Ellipse is circle\n                    if (GeometRi3D.AlmostEqual(e.A, e.B))\n                    {\n                        // Second ellipse also circle\n                        bool res1 = this.Center == e.Center && GeometRi3D.AlmostEqual(this.A, e.A);\n                        GeometRi3D.UseAbsoluteTolerance = false;\n                        GeometRi3D.Tolerance = tol;\n                        bool res2 = e.Normal.IsParallelTo(this.Normal);\n                        return res1 && res2;\n                    }\n                    else\n                    {\n                        GeometRi3D.UseAbsoluteTolerance = false;\n                        GeometRi3D.Tolerance = tol;\n                        return false;\n                    }\n                }\n                else\n                {\n                    bool res1 = this.Center == e.Center && GeometRi3D.AlmostEqual(this.A, e.A) && GeometRi3D.AlmostEqual(this.B, e.B);\n                    GeometRi3D.UseAbsoluteTolerance = false;\n                    GeometRi3D.Tolerance = tol;\n                    bool res2 = e.MajorSemiaxis.IsParallelTo(this.MajorSemiaxis) && e.MinorSemiaxis.IsParallelTo(this.MinorSemiaxis);\n                    return res1 && res2;\n                }\n            }\n\n\n        }\n\n        /// <summary>\n        /// Returns the hashcode for the object.\n        /// </summary>\n        public override int GetHashCode()\n        {\n            return GeometRi3D.HashFunction(_point.GetHashCode(), _v1.GetHashCode(), _v2.GetHashCode());\n        }\n\n        /// <summary>\n        /// String representation of an object in global coordinate system.\n        /// </summary>\n        public override String ToString()\n        {\n            return ToString(Coord3d.GlobalCS);\n        }\n\n        /// <summary>\n        /// String representation of an object in reference coordinate system.\n        /// </summary>\n        public String ToString(Coord3d coord)\n        {\n            string nl = System.Environment.NewLine;\n\n            if (coord == null) { coord = Coord3d.GlobalCS; }\n            Point3d P = _point.ConvertTo(coord);\n            Vector3d v1 = _v1.ConvertTo(coord);\n            Vector3d v2 = _v2.ConvertTo(coord);\n\n            string str = string.Format(\"Ellipse: \") + nl;\n            str += string.Format(\"  Center -> ({0,10:g5}, {1,10:g5}, {2,10:g5})\", P.X, P.Y, P.Z) + nl;\n            str += string.Format(\"  Semiaxis A -> ({0,10:g5}, {1,10:g5}, {2,10:g5})\", v1.X, v1.Y, v1.Z) + nl;\n            str += string.Format(\"  Semiaxis B -> ({0,10:g5}, {1,10:g5}, {2,10:g5})\", v2.X, v2.Y, v2.Z) + nl;\n            return str;\n        }\n\n        // Operators overloads\n        //-----------------------------------------------------------------\n\n        public static bool operator ==(Ellipse c1, Ellipse c2)\n        {\n            if (object.ReferenceEquals(c1, null))\n                return object.ReferenceEquals(c2, null);\n            return c1.Equals(c2);\n        }\n        public static bool operator !=(Ellipse c1, Ellipse c2)\n        {\n            if (object.ReferenceEquals(c1, null))\n                return !object.ReferenceEquals(c2, null);\n            return !c1.Equals(c2);\n        }\n\n    }\n}\n\n"
  },
  {
    "path": "GeometRi/Ellipsoid.cs",
    "content": "﻿using System;\nusing static System.Math;\n\nnamespace GeometRi\n{\n    /// <summary>\n    /// Ellipsoid object defined by center point and three mutually orthogonal vectors.\n    /// </summary>\n#if NET20_OR_GREATER\n    [Serializable]\n#endif\n    public class Ellipsoid : FiniteObject, IFiniteObject\n    {\n\n        private Point3d _point;\n        private Vector3d _v1;\n        private Vector3d _v2;\n        private Vector3d _v3;\n\n        /// <summary>\n        /// Initializes ellipsoid instance using center point and three orthogonal vectors.\n        /// </summary>\n        /// <param name=\"Center\">Center point.</param>\n        /// <param name=\"v1\">First semiaxis.</param>\n        /// <param name=\"v2\">Second semiaxis.</param>\n        /// <param name=\"v3\">Third semiaxis.</param>\n        public Ellipsoid(Point3d Center, Vector3d v1, Vector3d v2, Vector3d v3)\n        {\n            if ( !(v1.IsOrthogonalTo(v2) && v1.IsOrthogonalTo(v3) && v3.IsOrthogonalTo(v2)) )\n            {\n                throw new Exception(\"Semiaxes are not orthogonal\");\n            }\n            _point = Center.Copy();\n            if (v1.Norm >= v2.Norm && v1.Norm >= v3.Norm)\n            {\n                _v1 = v1.Copy();\n                if (v2.Norm >= v3.Norm)\n                {\n                    _v2 = v2.Copy();\n                    _v3 = v3.Copy();\n                }\n                else\n                {\n                    _v2 = v3.Copy();\n                    _v3 = v2.Copy();\n                }\n            }\n            else if (v2.Norm >= v1.Norm && v2.Norm >= v3.Norm)\n            {\n                _v1 = v2.Copy();\n                if (v1.Norm >= v3.Norm)\n                {\n                    _v2 = v1.Copy();\n                    _v3 = v3.Copy();\n                }\n                else\n                {\n                    _v2 = v3.Copy();\n                    _v3 = v1.Copy();\n                }\n            }\n            else\n            {\n                _v1 = v3.Copy();\n                if (v1.Norm >= v2.Norm)\n                {\n                    _v2 = v1.Copy();\n                    _v3 = v2.Copy();\n                }\n                else\n                {\n                    _v2 = v2.Copy();\n                    _v3 = v1.Copy();\n                }\n            }\n        }\n\n        /// <summary>\n        /// Creates copy of the object\n        /// </summary>\n        public Ellipsoid Copy()\n        {\n            return new Ellipsoid(_point.Copy(), _v1.Copy(), _v2.Copy(), _v3.Copy());\n        }\n\n        #region \"Properties\"\n        public Point3d Center\n        {\n            get { return _point; }\n        }\n\n        /// <summary>\n        /// Major semiaxis\n        /// </summary>\n        public Vector3d SemiaxisA\n        {\n            get { return _v1; }\n        }\n\n        /// <summary>\n        /// Intermediate semiaxis\n        /// </summary>\n        public Vector3d SemiaxisB\n        {\n            get { return _v2; }\n        }\n\n        /// <summary>\n        /// Minor semiaxis\n        /// </summary>\n        public Vector3d SemiaxisC\n        {\n            get { return _v3; }\n        }\n\n        /// <summary>\n        /// Length of the major semiaxis\n        /// </summary>\n        public double A\n        {\n            get { return _v1.Norm; }\n        }\n\n        /// <summary>\n        /// Length of the intermediate semiaxis\n        /// </summary>\n        public double B\n        {\n            get { return _v2.Norm; }\n        }\n\n        /// <summary>\n        /// Length of the minor semiaxis\n        /// </summary>\n        public double C\n        {\n            get { return _v3.Norm; }\n        }\n\n        /// <summary>\n        /// Volume of the ellipsoid\n        /// </summary>\n        public double Volume\n        {\n            get { return 4.0 / 3.0 * PI * A * B * C; }\n        }\n\n        /// <summary>\n        /// Approximate surface area of the ellipsoid (accurate up to 1.061%).\n        /// </summary>\n        public double Area\n        {\n            get {\n                double p = 1.6075;\n                double tmp = Pow(A * B, p) + Pow(A * C, p) + Pow(C * B, p);\n                return 4.0 * PI * Pow(tmp, 1/p);\n            }\n        }\n\n        /// <summary>\n        /// 3x3 covariance matrix\n        /// </summary>\n        public Matrix3d CovarianceMatrix\n        {\n            get\n            {\n                Vector3d v1 = _v1.Normalized;\n                Vector3d v2 = _v2.Normalized;\n                Vector3d v3 = _v3.Normalized;\n                Matrix3d m = new Matrix3d(v1, v2, v3);\n                Matrix3d D = Matrix3d.DiagonalMatrix(1 / (A * A), 1 / (B * B), 1 / (C * C));\n                return m * D * m.Transpose();\n            }\n        }\n        #endregion\n\n        #region \"BoundingBox\"\n        /// <summary>\n        /// Return minimum bounding box.\n        /// </summary>\n        public Box3d MinimumBoundingBox\n        {\n            get\n            {\n                Vector3d v1 = _v1.Normalized;\n                Vector3d v2 = _v2.Normalized;\n                Vector3d v3 = _v3.Normalized;\n                Matrix3d m = new Matrix3d(v1, v2, v3);\n                Rotation r = new Rotation(m.Transpose());\n                return new Box3d(_point, 2.0 * this.A, 2.0 * this.B, 2.0 * this.C, r);\n            }\n        }\n\n        /// <summary>\n        /// Return Bounding Box in given coordinate system.\n        /// </summary>\n        public Box3d BoundingBox(Coord3d coord = null)\n        {\n            coord = (coord == null) ? Coord3d.GlobalCS : coord;\n            Line3d l1 = new Line3d(coord.Origin, coord.Xaxis);\n            Line3d l2 = new Line3d(coord.Origin, coord.Yaxis);\n            Line3d l3 = new Line3d(coord.Origin, coord.Zaxis);\n            Segment3d s1 = this.ProjectionTo(l1);\n            Segment3d s2 = this.ProjectionTo(l2);\n            Segment3d s3 = this.ProjectionTo(l3);\n            return new Box3d(_point, s1.Length, s2.Length, s3.Length, coord);\n        }\n\n        /// <summary>\n        /// Return Axis Aligned Bounding Box (AABB).\n        /// </summary>\n        public AABB AABB()\n        {\n            Line3d l1 = new Line3d(_point, Coord3d.GlobalCS.Xaxis);\n            Line3d l2 = new Line3d(_point, Coord3d.GlobalCS.Yaxis);\n            Line3d l3 = new Line3d(_point, Coord3d.GlobalCS.Zaxis);\n            Segment3d s1 = this.ProjectionTo(l1);\n            Segment3d s2 = this.ProjectionTo(l2);\n            Segment3d s3 = this.ProjectionTo(l3);\n            return new AABB(_point, s1.Length, s2.Length, s3.Length);\n        }\n\n        /// <summary>\n        /// Return bounding sphere.\n        /// </summary>\n        public Sphere BoundingSphere\n        {\n            get { return new Sphere(_point, this.A); }\n\n        }\n        #endregion\n\n        /// <summary>\n        /// Orthogonal projection of ellipsoid to line.\n        /// </summary>\n        public Segment3d ProjectionTo(Line3d l)\n        {\n            //Stephen B. Pope \"Algorithms for Ellipsoids\"\n            // https://tcg.mae.cornell.edu/pubs/Pope_FDA_08.pdf\n\n            Coord3d lc = new Coord3d(_point, _v1, _v2);\n            Point3d x0 = l.Point.ConvertTo(lc);\n            Vector3d v = l.Direction.ConvertTo(lc);\n\n            Matrix3d L_T = Matrix3d.DiagonalMatrix(this.A, this.B, this.C);\n            Vector3d c = new Vector3d(0.0, 0.0, 0.0, lc);\n            double s0 = v * (c - x0.ToVector) / (v * v);\n            Vector3d w = L_T * v / (v * v);\n            Point3d P1 = x0.Translate((s0 + w.Norm) * v);\n            Point3d P2 = x0.Translate((s0 - w.Norm) * v);\n            return new Segment3d(P1, P2);\n        }\n\n        /// <summary>\n        /// Intersection of ellipsoid with line.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'.\n        /// </summary>\n        public object IntersectionWith(Line3d s)\n        {\n            // Analytical solution from:\n            // https://johannesbuchner.github.io/intersection/intersection_line_ellipsoid.html\n\n            // Define local cordinate system for ellipsoid\n            // and present line in parametric form in local coordinate system\n            // x: t + x0\n            // y: k * t + y0\n            // z: l * t + z0\n            // For numerical stability choose local X axis such that k<=1 and l<=1 !!!\n\n            Coord3d lc = new Coord3d(_point, _v1, _v2);\n            Vector3d v0 = s.Direction.ConvertTo(lc);\n            double a = A;\n            double b = B;\n            double c = C;\n            if (Abs(v0.Y) > Abs(v0.X) || Abs(v0.Z) > Abs(v0.X))\n            {\n                // Bad choice of X axis, try again\n                lc = new Coord3d(_point, _v2, _v3);\n                v0 = s.Direction.ConvertTo(lc);\n                a = B;\n                b = C;\n                c = A;\n                if (Abs(v0.Y) > Abs(v0.X) || Abs(v0.Z) > Abs(v0.X))\n                {\n                    lc = new Coord3d(_point, _v3, _v1);\n                    v0 = s.Direction.ConvertTo(lc);\n                    a = C;\n                    b = A;\n                    c = B;\n                }\n            }\n            // Normalize direction vector\n            double k = v0.Y / v0.X;\n            double l = v0.Z / v0.X;\n\n            Point3d p0 = s.Point.ConvertTo(lc);\n            double x0 = p0.X;\n            double y0 = p0.Y;\n            double z0 = p0.Z;\n\n            double a2b2 = a * a * b * b;\n            double a2c2 = a * a * c * c;\n            double b2c2 = b * b * c * c;\n\n            double det = a2b2 * c * c * (a2b2 * l * l + a2c2 * k * k - a * a * k * k * z0 * z0 +\n                                         2 * a * a * k * l * y0 * z0 - a * a * l * l * y0 * y0 + b2c2 -\n                                         b * b * l * l * x0 * x0 + 2 * b * b * l * x0 * z0 - b * b * z0 * z0 -\n                                         c * c * k * k * x0 * x0 + 2 * c * c * k * x0 * y0 - c * c * y0 * y0);\n\n            if (det < -GeometRi3D.Tolerance)\n            {\n                return null;\n            }\n\n            double sum1 = a2b2 * l * z0 + a2c2 * k * y0 + b2c2 * x0;\n            double sum2 = a2b2 * l * l + a2c2 * k * k + b2c2;\n\n            if (Abs(det) <= GeometRi3D.Tolerance)\n            {\n                // Intersection is point\n                double t = -sum1 / sum2;\n                return new Point3d(t + x0, k * t + y0, l * t + z0, lc);\n            }\n            else\n            {\n                double t = -(sum1 + Sqrt(det)) / sum2;\n                Point3d p1 = new Point3d(t + x0, k * t + y0, l * t + z0, lc);\n                t = -(sum1 - Sqrt(det)) / sum2;\n                Point3d p2 = new Point3d(t + x0, k * t + y0, l * t + z0, lc);\n                return new Segment3d(p1, p2);\n            }\n        }\n\n        /// <summary>\n        /// Intersection of ellipsoid with segment.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'.\n        /// </summary>\n        public object IntersectionWith(Segment3d s)\n        {\n\n            // Relative tolerance ================================\n            if (!GeometRi3D.UseAbsoluteTolerance)\n            {\n                double tol = GeometRi3D.Tolerance;\n                GeometRi3D.Tolerance = tol * this.A;\n                GeometRi3D.UseAbsoluteTolerance = true;\n                object result = this.IntersectionWith(s);\n                GeometRi3D.UseAbsoluteTolerance = false;\n                GeometRi3D.Tolerance = tol;\n                return result;\n            }\n            //====================================================\n\n            object obj = this.IntersectionWith(s.Line);\n\n            if (obj == null)\n            {\n                return null;\n            }\n            else if (obj.GetType() == typeof(Point3d))\n            {\n                Point3d p = (Point3d)obj;\n                if (p.BelongsTo(s))\n                {\n                    return p;\n                }\n                else\n                {\n                    return null;\n                }\n            }\n            else\n            {\n                return s.IntersectionWith((Segment3d)obj);\n            }\n        }\n\n        /// <summary>\n        /// Intersection of ellipsoid with ray.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'.\n        /// </summary>\n        public object IntersectionWith(Ray3d r)\n        {\n\n            // Relative tolerance ================================\n            if (!GeometRi3D.UseAbsoluteTolerance)\n            {\n                double tol = GeometRi3D.Tolerance;\n                GeometRi3D.Tolerance = tol * this.A;\n                GeometRi3D.UseAbsoluteTolerance = true;\n                object result = this.IntersectionWith(r);\n                GeometRi3D.UseAbsoluteTolerance = false;\n                GeometRi3D.Tolerance = tol;\n                return result;\n            }\n            //====================================================\n\n            object obj = this.IntersectionWith(r.ToLine);\n\n            if (obj == null)\n            {\n                return null;\n            }\n            else if (obj.GetType() == typeof(Point3d))\n            {\n                Point3d p = (Point3d)obj;\n                if (p.BelongsTo(r))\n                {\n                    return p;\n                }\n                else\n                {\n                    return null;\n                }\n            }\n            else\n            {\n                return r.IntersectionWith((Segment3d)obj);\n            }\n        }\n\n        /// <summary>\n        /// Intersection of ellipsoid with plane.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Ellipse'.\n        /// </summary>\n        public object IntersectionWith(Plane3d plane)\n        {\n            // Solution 1:\n            // Peter Paul Klein \n            // On the Ellipsoid and Plane Intersection Equation\n            // Applied Mathematics, 2012, 3, 1634-1640 (DOI:10.4236/am.2012.311226)\n\n            // Solution 2:\n            // Sebahattin Bektas\n            // Intersection of an Ellipsoid and a Plane\n            // International Journal of Research in Engineering and Applied Sciences, VOLUME 6, ISSUE 6 (June, 2016)\n\n            Coord3d lc = new Coord3d(_point, _v1, _v2, \"LC1\");\n            plane.SetCoord(lc);\n            double Ax, Ay, Az, Ad;\n            double a, b, c;\n            if (Abs(plane.C) >= Abs(plane.A) && Abs(plane.C) >= Abs(plane.B))\n            {\n                a = this.A; b = this.B; c = this.C;\n            }\n            else\n            {\n                lc = new Coord3d(_point, _v2, _v3, \"LC2\");\n                plane.SetCoord(lc);\n                if (Abs(plane.C) >= Abs(plane.A) && Abs(plane.C) >= Abs(plane.B))\n                {\n                    a = this.B; b = this.C; c = this.A;\n                }\n                else\n                {\n                    lc = new Coord3d(_point, _v3, _v1, \"LC3\");\n                    plane.SetCoord(lc);\n                    a = this.C; b = this.A; c = this.B;\n                }\n            }\n\n            Ax = plane.A; Ay = plane.B; Az = plane.C; Ad = plane.D;\n            double tmp = (Az * Az * c * c);\n            double AA = 1.0 / (a * a) + Ax * Ax / tmp;\n            double BB = 2.0 * Ax * Ay / tmp;\n            double CC = 1.0 / (b * b) + Ay * Ay / tmp;\n            double DD = 2.0 * Ax * Ad / tmp;\n            double EE = 2.0 * Ay * Ad / tmp;\n            double FF = Ad * Ad / tmp - 1.0;\n\n            double det = 4.0 * AA * CC - BB * BB;\n            if (GeometRi3D.AlmostEqual(det, 0))\n            {\n                return null;\n            }\n            double X0 = (BB * EE - 2 * CC * DD) / det;\n            double Y0 = (BB * DD - 2 * AA * EE) / det;\n            double Z0 = -(Ax * X0 + Ay * Y0 + Ad) / Az;\n\n            Point3d P0 = new Point3d(X0, Y0, Z0, lc);\n            if (P0.IsOnBoundary(this))\n                {\n                    // the plane is tangent to ellipsoid\n                    return P0;\n            }\n            else if (P0.IsInside(this))\n            {\n                Vector3d q = P0.ToVector.ConvertTo(lc);\n                Matrix3d D1 = Matrix3d.DiagonalMatrix(1 / a, 1 / b, 1 / c);\n                Vector3d r = plane.Normal.ConvertTo(lc).OrthogonalVector.Normalized;\n                Vector3d s = plane.Normal.ConvertTo(lc).Cross(r).Normalized;\n\n                double omega = 0;\n                double qq, qr, qs, rr, ss, rs;\n                if (!GeometRi3D.AlmostEqual((D1*r)*(D1*s),0))\n                {\n                    rr = (D1 * r) * (D1 * r);\n                    rs = (D1 * r) * (D1 * s);\n                    ss = (D1 * s) * (D1 * s);\n                    if (GeometRi3D.AlmostEqual(rr-ss, 0))\n                    {\n                        omega = PI / 4;\n                    }\n                    else\n                    {\n                        omega = 0.5 * Atan(2.0 * rs / (rr - ss));\n                    }\n                    Vector3d rprim = Cos(omega) * r + Sin(omega) * s;\n                    Vector3d sprim = -Sin(omega) * r + Cos(omega) * s;\n                    r = rprim;\n                    s = sprim;\n                }\n\n                qq = (D1 * q) * (D1 * q);\n                qr = (D1 * q) * (D1 * r);\n                qs = (D1 * q) * (D1 * s);\n                rr = (D1 * r) * (D1 * r);\n                ss = (D1 * s) * (D1 * s);\n\n                double d = qq - qr * qr / rr - qs * qs / ss;\n                AA = Sqrt((1 - d) / rr);\n                BB = Sqrt((1 - d) / ss);\n\n                return new Ellipse(P0, AA * r, BB * s);\n\n            }\n            else\n            {\n                return null;\n            }\n\n        }\n\n        /// <summary>\n        /// Check intesection of ellipsoid and sphere.\n        /// </summary>\n        public bool Intersects(Sphere e, double accuracy)\n        {\n            return _Intersects(e, accuracy) == 1 ? false : true;\n        }\n\n        /// <summary>\n        /// Check intesection of ellipsoid and sphere.\n        /// </summary>\n        public bool Intersects(Sphere e)\n        {\n            return _Intersects(e, GeometRi3D.DefaultTolerance) == 1 ? false : true;\n        }\n\n        /// <summary>\n        /// Check intesection of ellipsoid and sphere. Return values:\n        /// 1 - separate\n        /// 0 - externaly touch\n        /// -1 - overlap\n        /// </summary>\n        public int IntersectionCheck(Sphere e)\n        {\n            return _Intersects(e, GeometRi3D.DefaultTolerance);\n        }\n\n        /// <summary>\n        /// Check intesection of ellipsoid and sphere. Return values:\n        /// 1 - separate\n        /// 0 - externaly touch\n        /// -1 - overlap\n        /// </summary>\n        public int IntersectionCheck(Sphere e, double accuracy)\n        {\n            return _Intersects(e, accuracy);\n        }\n\n        /// <summary>\n        /// Check intesection of ellipsoid and sphere. Return values:\n        /// 1 - separate;\n        /// 0 - externaly touch;\n        /// -1 - overlap\n        /// </summary>\n        internal int _Intersects(Sphere e, double accuracy)\n        {\n            // Wang, W., Wang, J., & Kim, M. S. (2001). An algebraic condition for the separation of two ellipsoids. Computer aided geometric design, 18(6), 531-539.\n            // Jia, X., Choi, Y. K., Mourrain, B., & Wang, W. (2011). An algebraic approach to continuous collision detection for ellipsoids. Computer aided geometric design, 28(3), 164-176.\n\n            // 0 < a <= b <= c\n            Coord3d lc = new Coord3d(this.Center, this.SemiaxisC, this.SemiaxisB);\n\n            Point3d p = e.Center.ConvertTo(lc);\n            double x = p.X;\n            double y = p.Y;\n            double z = p.Z;\n            double r = e.R;\n\n            // 0 < a <= b <= c\n            double a2 = 1.0 / (this.SemiaxisC * this.SemiaxisC);\n            double b2 = 1.0 / (this.SemiaxisB * this.SemiaxisB);\n            double c2 = 1.0 / (this.SemiaxisA * this.SemiaxisA);\n\n            //  f(l) = k4*l^4 + k3*l^3 + k2*l^2 + k1*l +k0\n            double k0 = -r * r;\n            double k1 = a2 * (x * x - r * r) + b2 * (y * y - r * r) + c2 * (z * z - r * r) - 1;\n            double k2 = -(a2 + b2 + c2) + a2 * b2 * (x * x + y * y - r * r) +\n                                          a2 * c2 * (x * x + z * z - r * r) +\n                                          b2 * c2 * (z * z + y * y - r * r);\n            double k3 = -(a2 * b2 + a2 * c2 + b2 * c2) + a2 * b2 * c2 * (x * x + y * y + z * z - r * r);\n            double k4 = -a2 * b2 * c2;\n\n            // f(l) = l^4 + a*l^3 + b*l^2 + c*l + d\n            double a = k3 / k4;\n            double b = k2 / k4;\n            double c = k1 / k4;\n            double d = k0 / k4;\n\n            int count = 0;\n            if (Sign(1) != Sign(a)) count++;\n            if (Sign(a) != Sign(b)) count++;\n            if (Sign(b) != Sign(c)) count++;\n            if (Sign(c) != Sign(d)) count++;\n\n            double bbar = -a / 4;\n            double cbar = b / 6;\n            double dbar = -c / 4;\n            double ebar = d;\n\n            double d2 = bbar * bbar - cbar;\n            double d3 = cbar * cbar - bbar * dbar;\n\n            double W1 = dbar - bbar * cbar;\n            double W2 = bbar * ebar - cbar * dbar;\n            double W3 = ebar - bbar * dbar;\n\n            double T = -9 * W1 * W1 + 27 * d2 * d3 - 3 * W3 * d2;\n            double A = W3 + 3 * d3;\n            double B = -dbar * W1 - ebar * d2 - cbar * d3;\n            double T2 = A * W1 - 3 * bbar * B;\n            double d1 = A * A * A - 27 * B * B;\n\n            double sr22 = d2;\n            double sr20 = -W3;\n            double sr11 = T;\n            double sr10 = T2;\n            double sr0 = d1;\n\n            if (count == 2 && sr22 > 0 && sr11 > accuracy && sr0 > accuracy) return 1;\n            if (count == 2 && sr22 > 0 && sr11 > accuracy && sr10 > 0 && Abs(sr0) <= accuracy) return 1;\n            if (sr22 > 0 && sr11 > accuracy && sr10 < 0 && Abs(sr0) <= accuracy) return 0;\n            if (sr22 > 0 && sr20 < 0 && Abs(sr11) <= accuracy && Abs(sr0) <= accuracy) return 0;\n\n            return -1;\n        }\n\n        /// <summary>\n        /// Check intesection of two ellipsoids.\n        /// </summary>\n        private bool Intersects(Ellipsoid e, double accuracy)\n        {\n            return _Intersects(e, accuracy) == 1 ? false : true;\n        }\n\n        /// <summary>\n        /// Check intesection of two ellipsoids.\n        /// </summary>\n        private bool Intersects(Ellipsoid e)\n        {\n            return _Intersects(e, GeometRi3D.DefaultTolerance) == 1 ? false : true;\n        }\n\n        /// <summary>\n        /// Check intesection of two ellipsoids. Return values:\n        /// 1 - separate\n        /// 0 - externaly touch\n        /// -1 - overlap\n        /// </summary>\n        private int IntersectionCheck(Ellipsoid e)\n        {\n            return _Intersects(e, GeometRi3D.DefaultTolerance);\n        }\n\n        /// <summary>\n        /// Check intesection of two ellipsoids. Return values:\n        /// 1 - separate\n        /// 0 - externaly touch\n        /// -1 - overlap\n        /// </summary>\n        private int IntersectionCheck(Ellipsoid e, double accuracy)\n        {\n            return _Intersects(e, accuracy);\n        }\n\n        /// <summary>\n        /// Check intesection of two ellipsoids. Return values:\n        /// 1 - separate;\n        /// 0 - externaly touch;\n        /// -1 - overlap\n        /// </summary>\n        internal int _Intersects(Ellipsoid e, double accuracy)\n        {\n            // Jia, X., Choi, Y. K., Mourrain, B., & Wang, W. (2011). An algebraic approach to continuous collision detection for ellipsoids. Computer aided geometric design, 28(3), 164-176.\n\n            Coord3d lc = new Coord3d(this.Center, this.SemiaxisA, this.SemiaxisB);\n\n            Vector3d v1 = e._v1.Normalized.ConvertTo(lc);\n            Vector3d v2 = e._v2.Normalized.ConvertTo(lc);\n            Vector3d v3 = e._v3.Normalized.ConvertTo(lc);\n            Matrix3d m = new Matrix3d(v1, v2, v3);\n            Matrix3d D = Matrix3d.DiagonalMatrix(1 / (e.A * e.A), 1 / (e.B * e.B), 1 / (e.C * e.C));\n            //Matrix3d C = m * D * m.Transpose();\n            Matrix3d C = m.Transpose() * D * m;\n\n            double b11 = C[0, 0];\n            double b12 = C[0, 1];\n            double b13 = C[0, 2];\n            double b22 = C[1, 1];\n            double b23 = C[1, 2];\n            double b33 = C[2, 2];\n\n            Point3d p = e.Center.ConvertTo(lc);\n            Point3d bv = -C * p;\n            double b14 = bv.X;\n            double b24 = bv.Y;\n            double b34 = bv.Z;\n            double b44 = p.X * p.X + p.Y * p.Y + p.Z * p.Z - 1;\n\n            double a11 = 1.0 / (this.SemiaxisA * this.SemiaxisA);\n            double a22 = 1.0 / (this.SemiaxisB * this.SemiaxisB);\n            double a33 = 1.0 / (this.SemiaxisC * this.SemiaxisC);\n            double a44 = -1;\n\n            //  f(l) = k4*l^4 + k3*l^3 + k2*l^2 + k1*l +k0\n            double k0 = b14 * b14 * b23 * b23 - 2 * b13 * b14 * b23 * b24 + b13 * b13 * b24 * b24 - b14 * b14 * b22 * b33 +\n                        2 * b12 * b14 * b24 * b33 - b11 * b24 * b24 * b33 + 2 * b13 * b14 * b22 * b34 -\n                        2 * b12 * b14 * b23 * b34 - 2 * b12 * b13 * b24 * b34 + 2 * b11 * b23 * b24 * b34 +\n                        b12 * b12 * b34 * b34 - b11 * b22 * b34 * b34 - b13 * b13 * b22 * b44 + 2 * b12 * b13 * b23 * b44 -\n                        b11 * b23 * b23 * b44 - b12 * b12 * b33 * b44 + b11 * b22 * b33 * b44;\n            double k1 = -a44 * b13 * b13 * b22 -\n                        a33 * b14 * b14 * b22 + 2 * a44 * b12 * b13 * b23 - a44 * b11 * b23 * b23 +\n                        2 * a33 * b12 * b14 * b24 - a33 * b11 * b24 * b24 - a44 * b12 * b12 * b33 - a22 * b14 * b14 * b33 +\n                        a44 * b11 * b22 * b33 - a11 * b24 * b24 * b33 + 2 * a22 * b13 * b14 * b34 +\n                        2 * a11 * b23 * b24 * b34 - a22 * b11 * b34 * b34 - a11 * b22 * b34 * b34 - a33 * b12 * b12 * b44 -\n                        a22 * b13 * b13 * b44 + a33 * b11 * b22 * b44 - a11 * b23 * b23 * b44 + a22 * b11 * b33 * b44 +\n                        a11 * b22 * b33 * b44;\n            double k2 = -a33 * a44 * b12 * b12 - a22 * a44 * b13 * b13 - a22 * a33 * b14 * b14 +\n                        a33 * a44 * b11 * b22 - a11 * a44 * b23 * b23 - a11 * a33 * b24 * b24 + a22 * a44 * b11 * b33 +\n                        a11 * a44 * b22 * b33 - a11 * a22 * b34 * b34 + a22 * a33 * b11 * b44 +\n                        a11 * a33 * b22 * b44 + a11 * a22 * b33 * b44;\n            double k3 = a22 * a33 * a44 * b11 + a11 * a33 * a44 * b22 + a11 * a22 * a44 * b33 + a11 * a22 * a33 * b44;\n            double k4 = a11 * a22 * a33 * a44;\n\n            // f(l) = l^4 + a*l^3 + b*l^2 + c*l + d\n            double a = k3 / k4;\n            double b = k2 / k4;\n            double c = k1 / k4;\n            double d = k0 / k4;\n\n            int count = 0;\n            if (Sign(1) != Sign(a)) count++;\n            if (Sign(a) != Sign(b)) count++;\n            if (Sign(b) != Sign(c)) count++;\n            if (Sign(c) != Sign(d)) count++;\n\n            double bbar = -a / 4;\n            double cbar = b / 6;\n            double dbar = -c / 4;\n            double ebar = d;\n\n            double d2 = bbar * bbar - cbar;\n            double d3 = cbar * cbar - bbar * dbar;\n\n            double W1 = dbar - bbar * cbar;\n            double W2 = bbar * ebar - cbar * dbar;\n            double W3 = ebar - bbar * dbar;\n\n            double T = -9 * W1 * W1 + 27 * d2 * d3 - 3 * W3 * d2;\n            double A = W3 + 3 * d3;\n            double B = -dbar * W1 - ebar * d2 - cbar * d3;\n            double T2 = A * W1 - 3 * bbar * B;\n            double d1 = A * A * A - 27 * B * B;\n\n            double sr22 = d2;\n            double sr20 = -W3;\n            double sr11 = T;\n            double sr10 = T2;\n            double sr0 = d1;\n\n            if (count == 2 && sr22 > 0 && sr11 > accuracy && sr0 > accuracy) return 1;\n            if (count == 2 && sr22 > 0 && sr11 > accuracy && sr10 > 0 && Abs(sr0) <= accuracy) return 1;\n            if (sr22 > 0 && sr11 > accuracy && sr10 < 0 && Abs(sr0) <= accuracy) return 0;\n            if (sr22 > 0 && sr20 < 0 && Abs(sr11) <= accuracy && Abs(sr0) <= accuracy) return 0;\n\n            return -1;\n        }\n\n        internal override int _PointLocation(Point3d p)\n        {\n\n            Coord3d lc = new Coord3d(this.Center, this.SemiaxisA, this.SemiaxisB);\n            p = p.ConvertTo(lc);\n\n            if (GeometRi3D.UseAbsoluteTolerance)\n            {\n                double dist = this.ClosestPoint(p).DistanceTo(p);\n                if (GeometRi3D.AlmostEqual(dist, 0))\n                {\n                    return 0; // Point is on boundary\n                }\n                if (GeometRi3D.Smaller(p.X * p.X / (A*A) + p.Y * p.Y / (B*B) + p.Z * p.Z / (C*C), 1.0))\n                {\n                    return 1; // Point is strictly inside box\n                }\n\n                return -1; // Point is outside\n\n            }\n            else\n            {\n                double tol = GeometRi3D.Tolerance;\n                GeometRi3D.Tolerance = tol * this.A;\n                GeometRi3D.UseAbsoluteTolerance = true;\n                int result = this._PointLocation(p);\n                GeometRi3D.UseAbsoluteTolerance = false;\n                GeometRi3D.Tolerance = tol;\n                return result;\n            }\n        }\n\n        /// <summary>\n        /// Calculates the point on the ellipsoid's boundary closest to given point.\n        /// </summary>\n        public Point3d ClosestPoint(Point3d p)\n        {\n            return this.ClosestPoint(p, GeometRi3D.Tolerance);\n        }\n\n        /// <summary>\n        /// Calculates the point on the ellipsoid's boundary closest to given point.\n        /// </summary>\n        public Point3d ClosestPoint(Point3d p, double tolerance)\n        {\n\n            // Algorithm by Dr. Robert Nurnberg\n            // https://nurnberg.maths.unitn.it/distance2ellipse.pdf\n\n            Coord3d local_coord = new Coord3d(this.Center, this._v1, this._v2);\n            p = p.ConvertTo(local_coord);\n\n            if (GeometRi3D.AlmostEqual(p.X, 0) && GeometRi3D.AlmostEqual(p.Y, 0))\n            {\n                // Center point, choose any minor-axis\n                return new Point3d(0, C, 0, local_coord);\n            }\n\n            double theta = Atan2(A * p.Y, B * p.X);\n            double phi = Atan2(p.Z, C * Sqrt((p.X*p.X)/(A*A) + (p.Y*p.Y)/(B*B)));\n            int iter = 0;\n            int max_iter = 100;\n            Point3d n0 = p.Copy();\n\n            while (iter < max_iter)\n            {\n                iter += 1;\n                double ct = Cos(theta);\n                double st = Sin(theta);\n                double cp = Cos(phi);\n                double sp = Sin(phi);\n\n                double F1 = (A * A - B * B) * ct * st * cp - p.X * A * st + p.Y * B * ct;\n                double F2 = (A * A * ct * ct + B * B * st * st - C * C) * sp * cp - p.X * A * sp * ct - p.Y * B * sp * st + p.Z * C * cp;\n\n                double a11 = (A * A - B * B) * (ct * ct - st * st) * cp - p.X * A * ct - p.Y * B * st;\n                double a12 = -(A * A - B * B) * ct * st * sp;\n                double a21 = -2.0 * (A * A - B * B) * ct * st * cp * sp + p.X * A * sp * st - p.Y * B * sp * ct;\n                double a22 = (A * A * ct * ct + B * B * st * st - C * C) * (cp * cp - sp * sp) - p.X * A * cp * ct - p.Y * B * cp * st - p.Z * C * sp;\n\n                double det = a11 * a22 - a12 * a21;\n                if (det == 0) { throw new Exception(\"Zero determinant\"); }\n                // Calc reverse matrix B[ij] = A[ij]^-1\n                double b11 = a22 / det;\n                double b12 = -a12 / det;\n                double b21 = -a21 / det;\n                double b22 = a11 / det;\n\n                theta = theta - (b11 * F1 + b12 * F2);\n                phi = phi - (b21 * F1 + b22 * F2);\n\n                Point3d n = new Point3d(A * Cos(phi)*Cos(theta), B * Cos(phi)*Sin(theta), C*Sin(phi), local_coord);\n\n                if (n0.DistanceTo(n) < tolerance)\n                {\n                    return n;\n                }\n                n0 = n.Copy();\n            }\n\n            return n0;\n        }\n\n\n        /// <summary>\n        /// Distance between two ellipsoids.\n        /// </summary>\n        public double DistanceTo(Ellipsoid e)\n        {\n            return this.DistanceTo(e, GeometRi3D.Tolerance);\n        }\n\n        /// <summary>\n        /// Distance between two ellipsoids.\n        /// </summary>\n        public double DistanceTo(Ellipsoid e, double tolerance)\n        {\n            int iter = 0;\n            int max_iter = 100;\n            Point3d p1 = this.ClosestPoint(e.Center, tolerance);\n            Point3d p2 = e.ClosestPoint(p1, tolerance);\n            double old_distance = p1.DistanceTo(p2);\n\n            while (iter < max_iter)\n            {\n                iter += 1;\n                p1 = this.ClosestPoint(p2, tolerance);\n                p2 = e.ClosestPoint(p1, tolerance);\n                double dist = p1.DistanceTo(p2);\n                if (Abs(dist-old_distance) < tolerance)\n                {\n                    return dist;\n                }\n                old_distance = dist;\n            }\n            return old_distance;\n        }\n\n        #region \"TranslateRotateReflect\"\n        /// <summary>\n        /// Translate ellipsoid by a vector\n        /// </summary>\n        public Ellipsoid Translate(Vector3d v)\n        {\n            return new Ellipsoid(this.Center.Translate(v), _v1, _v2, _v3);\n        }\n\n        /// <summary>\n        /// Rotate ellipsoid by a given rotation matrix\n        /// </summary>\n        [System.Obsolete(\"use Rotation object and specify rotation center: this.Rotate(Rotation r, Point3d p)\")]\n        public Ellipsoid Rotate(Matrix3d m)\n        {\n            return new Ellipsoid(this.Center.Rotate(m), _v1.Rotate(m), _v2.Rotate(m), _v3.Rotate(m));\n        }\n\n        /// <summary>\n        /// Rotate ellipsoid by a given rotation matrix around point 'p' as a rotation center\n        /// </summary>\n        [System.Obsolete(\"use Rotation object: this.Rotate(Rotation r, Point3d p)\")]\n        public Ellipsoid Rotate(Matrix3d m, Point3d p)\n        {\n            return new Ellipsoid(this.Center.Rotate(m, p), _v1.Rotate(m), _v2.Rotate(m), _v3.Rotate(m));\n        }\n\n        /// <summary>\n        /// Rotate ellipsoid around point 'p' as a rotation center\n        /// </summary>\n        public Ellipsoid Rotate(Rotation r, Point3d p)\n        {\n            return new Ellipsoid(this.Center.Rotate(r, p), _v1.Rotate(r), _v2.Rotate(r), _v3.Rotate(r));\n        }\n\n        /// <summary>\n        /// Reflect ellipsoid in given point\n        /// </summary>\n        public Ellipsoid ReflectIn(Point3d p)\n        {\n            return new Ellipsoid(this.Center.ReflectIn(p), _v1.ReflectIn(p), _v2.ReflectIn(p), _v3.ReflectIn(p));\n        }\n\n        /// <summary>\n        /// Reflect ellipsoid in given line\n        /// </summary>\n        public Ellipsoid ReflectIn(Line3d l)\n        {\n            return new Ellipsoid(this.Center.ReflectIn(l), _v1.ReflectIn(l), _v2.ReflectIn(l), _v3.ReflectIn(l));\n        }\n\n        /// <summary>\n        /// Reflect ellipsoid in given plane\n        /// </summary>\n        public Ellipsoid ReflectIn(Plane3d s)\n        {\n            return new Ellipsoid(this.Center.ReflectIn(s), _v1.ReflectIn(s), _v2.ReflectIn(s), _v3.ReflectIn(s));\n        }\n\n        /// <summary>\n        /// Scale ellipsoid relative to given point\n        /// </summary>\n        public virtual Ellipsoid Scale(double scale, Point3d scaling_center)\n        {\n            Point3d new_center = scaling_center + scale * (this.Center - scaling_center);\n            return new Ellipsoid(new_center, _v1 * scale, _v2 * scale, _v3 * scale);\n        }\n        #endregion\n\n        /// <summary>\n        /// Determines whether two objects are equal.\n        /// </summary>\n        public override bool Equals(object obj)\n        {\n            if (obj == null || (!object.ReferenceEquals(this.GetType(), obj.GetType())))\n            {\n                return false;\n            }\n            Ellipsoid e = (Ellipsoid)obj;\n\n            if (GeometRi3D.UseAbsoluteTolerance)\n            {\n                if (this.Center != e.Center)\n                {\n                    return false;\n                }\n\n                if (GeometRi3D.AlmostEqual(this.A, this.B) && GeometRi3D.AlmostEqual(this.A, this.C))\n                {\n                    // Ellipsoid is sphere\n                    if (GeometRi3D.AlmostEqual(e.A, e.B) && GeometRi3D.AlmostEqual(e.A, e.C))\n                    {\n                        // Second ellipsoid also sphere\n                        return GeometRi3D.AlmostEqual(this.A, e.A);\n                    }\n                    else\n                    {\n                        return false;\n                    }\n                }\n                else if (GeometRi3D.AlmostEqual(this.A, this.B) && GeometRi3D.AlmostEqual(e.A, e.B))\n                {\n                    return GeometRi3D.AlmostEqual(this.A, e.A) && GeometRi3D.AlmostEqual(this.C, e.C) &&\n                           e.SemiaxisC.IsParallelTo(this.SemiaxisC);\n                }\n                else if (GeometRi3D.AlmostEqual(this.A, this.C) && GeometRi3D.AlmostEqual(e.A, e.C))\n                {\n                    return GeometRi3D.AlmostEqual(this.A, e.A) && GeometRi3D.AlmostEqual(this.B, e.B) &&\n                           e.SemiaxisB.IsParallelTo(this.SemiaxisB);\n                }\n                else if (GeometRi3D.AlmostEqual(this.C, this.B) && GeometRi3D.AlmostEqual(e.C, e.B))\n                {\n                    return GeometRi3D.AlmostEqual(this.A, e.A) && GeometRi3D.AlmostEqual(this.C, e.C) &&\n                           e.SemiaxisA.IsParallelTo(this.SemiaxisA);\n                }\n                else\n                {\n                    return GeometRi3D.AlmostEqual(this.A, e.A) && e.SemiaxisA.IsParallelTo(this.SemiaxisA) &&\n                           GeometRi3D.AlmostEqual(this.B, e.B) && e.SemiaxisB.IsParallelTo(this.SemiaxisB) &&\n                           GeometRi3D.AlmostEqual(this.C, e.C) && e.SemiaxisC.IsParallelTo(this.SemiaxisC);\n                }\n            }\n            else\n            {\n                double tol = GeometRi3D.Tolerance;\n                GeometRi3D.Tolerance = tol * e.SemiaxisA.Norm;\n                GeometRi3D.UseAbsoluteTolerance = true;\n\n                if (this.Center != e.Center)\n                {\n                    GeometRi3D.UseAbsoluteTolerance = false;\n                    GeometRi3D.Tolerance = tol;\n                    return false;\n                }\n\n                if (GeometRi3D.AlmostEqual(this.A, this.B) && GeometRi3D.AlmostEqual(this.A, this.C))\n                {\n                    // Ellipsoid is sphere\n                    if (GeometRi3D.AlmostEqual(e.A, e.B) && GeometRi3D.AlmostEqual(e.A, e.C))\n                    {\n                        // Second ellipsoid also sphere\n                        bool res =  GeometRi3D.AlmostEqual(this.A, e.A);\n                        GeometRi3D.UseAbsoluteTolerance = false;\n                        GeometRi3D.Tolerance = tol;\n                        return res;\n                    }\n                    else\n                    {\n                        GeometRi3D.UseAbsoluteTolerance = false;\n                        GeometRi3D.Tolerance = tol;\n                        return false;\n                    }\n                }\n                else if (GeometRi3D.AlmostEqual(this.A, this.B) && GeometRi3D.AlmostEqual(e.A, e.B))\n                {\n                    bool res1 = GeometRi3D.AlmostEqual(this.A, e.A) && GeometRi3D.AlmostEqual(this.C, e.C);\n                    GeometRi3D.UseAbsoluteTolerance = false;\n                    GeometRi3D.Tolerance = tol;\n                    bool res2 = e.SemiaxisC.IsParallelTo(this.SemiaxisC);\n                    return res1 && res2;\n                }\n                else if (GeometRi3D.AlmostEqual(this.A, this.C) && GeometRi3D.AlmostEqual(e.A, e.C))\n                {\n                    bool res1 = GeometRi3D.AlmostEqual(this.A, e.A) && GeometRi3D.AlmostEqual(this.B, e.B);\n                    GeometRi3D.UseAbsoluteTolerance = false;\n                    GeometRi3D.Tolerance = tol;\n                    bool res2 = e.SemiaxisB.IsParallelTo(this.SemiaxisB);\n                    return res1 && res2;\n                }\n                else if (GeometRi3D.AlmostEqual(this.C, this.B) && GeometRi3D.AlmostEqual(e.C, e.B))\n                {\n                    bool res1 = GeometRi3D.AlmostEqual(this.A, e.A) && GeometRi3D.AlmostEqual(this.C, e.C);\n                    GeometRi3D.UseAbsoluteTolerance = false;\n                    GeometRi3D.Tolerance = tol;\n                    bool res2 = e.SemiaxisA.IsParallelTo(this.SemiaxisA);\n                    return res1 && res2;\n                }\n                else\n                {\n                    bool res1 = GeometRi3D.AlmostEqual(this.A, e.A) && GeometRi3D.AlmostEqual(this.B, e.B) && GeometRi3D.AlmostEqual(this.C, e.C);\n                    GeometRi3D.UseAbsoluteTolerance = false;\n                    GeometRi3D.Tolerance = tol;\n                    bool res2 = e.SemiaxisA.IsParallelTo(this.SemiaxisA) && e.SemiaxisB.IsParallelTo(this.SemiaxisB) && e.SemiaxisC.IsParallelTo(this.SemiaxisC);\n                    return res1 && res2;\n                }\n            }\n\n\n        }\n\n        /// <summary>\n        /// Returns the hashcode for the object.\n        /// </summary>\n        public override int GetHashCode()\n        {\n            return GeometRi3D.HashFunction(_point.GetHashCode(), _v1.GetHashCode(), _v2.GetHashCode(), _v3.GetHashCode());\n        }\n\n        /// <summary>\n        /// String representation of an object in global coordinate system.\n        /// </summary>\n        public override String ToString()\n        {\n            return ToString(Coord3d.GlobalCS);\n        }\n\n        /// <summary>\n        /// String representation of an object in reference coordinate system.\n        /// </summary>\n        public String ToString(Coord3d coord)\n        {\n            string nl = System.Environment.NewLine;\n\n            if (coord == null) { coord = Coord3d.GlobalCS; }\n            Point3d P = _point.ConvertTo(coord);\n            Vector3d v1 = _v1.ConvertTo(coord);\n            Vector3d v2 = _v2.ConvertTo(coord);\n            Vector3d v3 = _v3.ConvertTo(coord);\n\n            string str = string.Format(\"Ellipsoid: \") + nl;\n            str += string.Format(\"  Center -> ({0,10:g5}, {1,10:g5}, {2,10:g5})\", P.X, P.Y, P.Z) + nl;\n            str += string.Format(\"  Semiaxis A -> ({0,10:g5}, {1,10:g5}, {2,10:g5})\", v1.X, v1.Y, v1.Z) + nl;\n            str += string.Format(\"  Semiaxis B -> ({0,10:g5}, {1,10:g5}, {2,10:g5})\", v2.X, v2.Y, v2.Z) + nl;\n            str += string.Format(\"  Semiaxis C -> ({0,10:g5}, {1,10:g5}, {2,10:g5})\", v3.X, v3.Y, v3.Z) + nl;\n            return str;\n        }\n\n        // Operators overloads\n        //-----------------------------------------------------------------\n\n        public static bool operator ==(Ellipsoid c1, Ellipsoid c2)\n        {\n            if (object.ReferenceEquals(c1, null))\n                return object.ReferenceEquals(c2, null);\n            return c1.Equals(c2);\n        }\n        public static bool operator !=(Ellipsoid c1, Ellipsoid c2)\n        {\n            if (object.ReferenceEquals(c1, null))\n                return !object.ReferenceEquals(c2, null);\n            return !c1.Equals(c2);\n        }\n    }\n}\n"
  },
  {
    "path": "GeometRi/GeometRi.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFrameworks>netstandard2.0;net461;netcoreapp3.1;net5.0</TargetFrameworks>\n    <RootNamespace>GeometRi</RootNamespace>\n    <AssemblyName>GeometRi</AssemblyName>\n    <Description>GeometRi is a simple and lightweight 3D geometry library for .Net. Its main purpose is manipulations with basic geometrical primitives, such as point, line, plane, segment in 3D space: translation and rotation operations, distance calculation, intersections, orthogonal projections of one object into another, etc. The basic objects can be defined in global or in one of the local coordinate systems and converted form one coordinate system into another. Each object stores its reference coordinate system and all necessary transformations are performed implicitly when needed.\n\nCompatible with .Net Framework 4.6.1, .Net Standard 2.0, .Net Core 3.1 and .Net 5.</Description>\n    <Copyright>Copyright (c) 2017-2026 Sergey Tarasov</Copyright>\n    <AssemblyVersion>1.5.0.9</AssemblyVersion>\n    <GeneratePackageOnBuild>true</GeneratePackageOnBuild>\n    <Authors>Sergey Tarasov</Authors>\n    <Company />\n    <PackageProjectUrl>https://github.com/RiSearcher/GeometRi.CSharp</PackageProjectUrl>\n    <Version>1.5.0.9</Version>\n    <PackageTags>computational geometry math 3D</PackageTags>\n    <PackageReleaseNotes>Fixed triangle-segment intersection.\nUnion of two AABB.\nSmall optimizations.</PackageReleaseNotes>\n    <PackageLicenseUrl></PackageLicenseUrl>\n    <RepositoryUrl>https://github.com/RiSearcher/GeometRi.CSharp</RepositoryUrl>\n    <PackageLicenseFile>LICENSE.txt</PackageLicenseFile>\n    <FileVersion>1.5.0.9</FileVersion>\n    <PackageReadmeFile>README.md</PackageReadmeFile>\n  </PropertyGroup>\n\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|AnyCPU'\">\n    <DocumentationFile>bin\\Debug\\netstandard1.0\\GeometRi.Standard.xml</DocumentationFile>\n  </PropertyGroup>\n\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|AnyCPU'\">\n    <DocumentationFile>bin\\Release\\netstandard1.0\\GeometRi.xml</DocumentationFile>\n    <NoWarn>1701;1702;1705;1591</NoWarn>\n  </PropertyGroup>\n\n  <PropertyGroup Condition=\"'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|netstandard1.0|AnyCPU'\">\n    <DefineConstants>DEBUG;TRACE</DefineConstants>\n    <OutputPath>bin\\Debug\\</OutputPath>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <None Include=\"..\\LICENSE.txt\">\n      <Pack>True</Pack>\n      <PackagePath></PackagePath>\n    </None>\n    <None Include=\"..\\README.md\">\n      <Pack>True</Pack>\n      <PackagePath>\\</PackagePath>\n    </None>\n  </ItemGroup>\n\n\n</Project>"
  },
  {
    "path": "GeometRi/GeometRi3D.cs",
    "content": "﻿using System;\nusing static System.Math;\n\nnamespace GeometRi\n{\n    /// <summary>\n    /// Static class. Implements global tolerance property and tolerance based equality methods.\n    /// </summary>\n    public static class GeometRi3D\n    {\n\n        private static double _tolerance = 1E-12;\n        private static double _default_tolerance = 1E-12;\n        private static bool _absolute = true;\n        internal static Random rnd;\n\n        /// <summary>\n        /// Tolerance used for comparison operations (default 1e-12)\n        /// </summary>\n        public static double Tolerance\n        {\n            get { return _tolerance; }\n            set { _tolerance = value; }\n        }\n\n        /// <summary>\n        /// Default tolerance used for comparison operations\n        /// </summary>\n        public static double DefaultTolerance\n        {\n            get { return _default_tolerance; }\n            set { _default_tolerance = value; }\n        }\n\n        /// <summary>\n        /// Flag for switching absolute (TRUE) to relative (FALSE) tolerance comparison.\n        /// </summary>\n        public static bool UseAbsoluteTolerance\n        {\n            get { return _absolute; }\n            set { _absolute = value; }\n        }\n\n        /// <summary>\n        /// Tolerance based equality check\n        /// </summary>\n        public static bool AlmostEqual(double a, double b)\n        {\n            if (Math.Abs(a - b) <= _tolerance)\n            {\n                return true;\n            }\n            else\n            {\n                return false;\n            }\n        }\n\n        /// <summary>\n        /// Tolerance based equality check\n        /// </summary>\n        public static bool AlmostEqual(double a, double b, double tolerance)\n        {\n            if (Math.Abs(a - b) <= tolerance)\n            {\n                return true;\n            }\n            else\n            {\n                return false;\n            }\n        }\n\n        /// <summary>\n        /// Tolerance based unequality check\n        /// </summary>\n        public static bool NotEqual(double a, double b)\n        {\n            if (Math.Abs(a - b) > _tolerance)\n            {\n                return true;\n            }\n            else\n            {\n                return false;\n            }\n        }\n\n        /// <summary>\n        /// Tolerance based unequality check\n        /// </summary>\n        public static bool NotEqual(double a, double b, double tolerance)\n        {\n            if (Math.Abs(a - b) > tolerance)\n            {\n                return true;\n            }\n            else\n            {\n                return false;\n            }\n        }\n\n        /// <summary>\n        /// Tolerance based comparison\n        /// </summary>\n        public static bool Greater(double a, double b)\n        {\n            if ((a - b) > _tolerance)\n            {\n                return true;\n            }\n            else\n            {\n                return false;\n            }\n        }\n\n        /// <summary>\n        /// Tolerance based comparison\n        /// </summary>\n        public static bool Greater(double a, double b, double tolerance)\n        {\n            if ((a - b) > tolerance)\n            {\n                return true;\n            }\n            else\n            {\n                return false;\n            }\n        }\n\n        /// <summary>\n        /// Tolerance based comparison\n        /// </summary>\n        public static bool Smaller(double a, double b)\n        {\n            if ((a - b) < -_tolerance)\n            {\n                return true;\n            }\n            else\n            {\n                return false;\n            }\n        }\n\n        /// <summary>\n        /// Tolerance based comparison\n        /// </summary>\n        public static bool Smaller(double a, double b, double tolerance)\n        {\n            if ((a - b) < -tolerance)\n            {\n                return true;\n            }\n            else\n            {\n                return false;\n            }\n        }\n\n        static internal int HashFunction(int n1, int n2)\n        {\n            return (n1 << 4) ^ (n1 >> 28) ^ n2;\n        }\n\n        static internal int HashFunction(int n1, int n2, int n3)\n        {\n            n1 = (n1 << 4) ^ (n1 >> 28) ^ n2;\n            return (n1 << 4) ^ (n1 >> 28) ^ n3;\n        }\n\n        static internal int HashFunction(int n1, int n2, int n3, int n4)\n        {\n            n1 = (n1 << 4) ^ (n1 >> 28) ^ n2;\n            n1 = (n1 << 4) ^ (n1 >> 28) ^ n3;\n            return (n1 << 4) ^ (n1 >> 28) ^ n4;\n        }\n\n        /// <summary>\n        /// Restrict 'value' to a range [min, max].\n        /// </summary>\n        public static T Clamp<T>(T value, T min, T max) where T : IComparable<T>\n        {\n            if (value == null || min == null || max == null) throw new ArgumentNullException();\n            // Check if min <= max\n            if (min.CompareTo(max) <= 0) return value.CompareTo(min) < 0 ? min : value.CompareTo(max) > 0 ? max : value;\n            // Reverse min and max otherwise\n            return value.CompareTo(max) < 0 ? max : value.CompareTo(min) > 0 ? min : value;\n        }\n\n        #region \"CalcAngle\"\n        static internal double GetAngle(ILinearObject obj1, ILinearObject obj2)\n        {\n            if (obj1.IsOriented && obj2.IsOriented)\n            {\n                double tmp = obj1.Direction.Dot(obj2.Direction);\n                if (tmp > 1)\n                {\n                    tmp = 1;\n                } else if (tmp < -1)\n                {\n                    tmp = -1;\n                }\n                return Acos(tmp);\n            }\n            else\n            {\n                // return smalest angle\n                double ang = GetAngle(obj1.Direction, obj2.Direction);\n                if (ang <= PI / 2)\n                {\n                    return ang;\n                }\n                else\n                {\n                    return PI - ang;\n                }\n            }\n        }\n\n        static internal double GetAngle(ILinearObject obj1, IPlanarObject obj2)\n        {\n            if (obj1.IsOriented && obj2.IsOriented)\n            {\n                throw new NotImplementedException();\n            }\n            else\n            {\n                double tmp = obj1.Direction.Dot(obj2.Normal);\n                if (tmp > 1)\n                {\n                    tmp = 1;\n                }\n                else if (tmp < -1)\n                {\n                    tmp = -1;\n                }\n                double ang = Asin(tmp);\n                return Abs(ang);\n            }\n        }\n\n        static internal double GetAngle(IPlanarObject obj1, ILinearObject obj2)\n        {\n            return GetAngle(obj2, obj1);\n        }\n\n        static internal double GetAngle(IPlanarObject obj1, IPlanarObject obj2)\n        {\n            if (obj1.IsOriented && obj2.IsOriented)\n            {\n                throw new NotImplementedException();\n            }\n            else\n            {\n                // return smalest angle\n                double ang = GetAngle(obj1.Normal, obj2.Normal);\n                if (ang <= PI / 2)\n                {\n                    return ang;\n                }\n                else\n                {\n                    return PI - ang;\n                }\n            }\n        }\n        #endregion\n\n        static internal bool _coplanar(IPlanarObject obj1, IPlanarObject obj2)\n        {\n            Plane3d plane1 = obj1 is PlanarFiniteObject pl1 ? pl1.Plane : obj1 is Plane3d p1? p1 : obj1.ToPlane;\n            Plane3d plane2 = obj2 is PlanarFiniteObject pl2 ? pl2.Plane : obj2 is Plane3d p2? p2 : obj2.ToPlane;\n\n            return plane1.Equals(plane2);\n        }\n\n        static internal bool _coplanar(ILinearObject obj1, ILinearObject obj2)\n        {\n            Line3d l1 = obj1 is LinearFiniteObject lin1 ? lin1.Line : obj1 is Line3d ? (Line3d)obj1 : obj1.ToLine;\n            Line3d l2 = obj2 is LinearFiniteObject lin2 ? lin2.Line : obj2 is Line3d ? (Line3d)obj2 : obj2.ToLine;\n            if (l1.IsParallelTo(l2))\n            {\n                return true;\n            }\n            return AlmostEqual(l1.DistanceTo(l2), 0.0);\n        }\n\n        static internal bool _coplanar(IPlanarObject obj1, ILinearObject obj2)\n        {\n            Plane3d plane1 = obj1 is PlanarFiniteObject pl1 ? pl1.Plane : obj1 is Plane3d p1? p1 : obj1.ToPlane;\n\n            return obj1.Normal.IsOrthogonalTo(obj2.Direction) && obj2.ToLine.Point.BelongsTo(plane1);\n        }\n\n        static internal bool _coplanar(ILinearObject obj1, IPlanarObject obj2)\n        {\n            return _coplanar(obj2, obj1);\n        }\n    }\n}\n"
  },
  {
    "path": "GeometRi/Interface.cs",
    "content": "﻿using System;\n\nnamespace GeometRi\n{\n\n    /// <summary>\n    /// Interface for 1D objects (vector, line, ray, segment)\n    /// </summary>\n    public interface ILinearObject\n    {\n        Vector3d Direction { get; }\n        bool IsOriented { get; }\n        Line3d ToLine { get; }\n    }\n\n    /// <summary>\n    /// Interface for 2D objects (plane, circle, ellipse, triangle)\n    /// </summary>\n    public interface IPlanarObject\n    {\n        Vector3d Normal { get; }\n        bool IsOriented { get; }\n        Plane3d ToPlane { get; }\n    }\n\n\n    /// <summary>\n    /// Interface for finite objects\n    /// </summary>\n    public interface IFiniteObject\n    {\n        Box3d BoundingBox(Coord3d coord);\n        Box3d MinimumBoundingBox { get; }\n        Sphere BoundingSphere { get; }\n    }\n\n    /// <summary>\n    /// Interface for basic operations with points and vectors\n    /// </summary>\n    public interface IVector\n    {\n        //Coord3d Coord { get; }\n        double Dot(IVector v);\n        IVector Subtract(IVector v);\n        double X { get; }\n        double Y { get; }\n        double Z { get; }\n    }\n}\n"
  },
  {
    "path": "GeometRi/Line3D.cs",
    "content": "﻿using System;\nusing static System.Math;\n\nnamespace GeometRi\n{\n    /// <summary>\n    /// Infinite line  in 3D space and defined by any point lying on the line and a direction vector.\n    /// </summary>\n#if NET20_OR_GREATER\n    [Serializable]\n#endif\n    public class Line3d : ILinearObject\n    {\n\n        private Point3d _point;\n        private Vector3d _dir;\n\n        internal bool HasChanged => _point.HasChanged || _dir.HasChanged;\n\n        #region \"Constructors\"\n        /// <summary>\n        /// Default constructor, initializes line aligned with X-axis in global coordinate system.\n        /// </summary>\n        public Line3d()\n        {\n            _point = new Point3d();\n            _dir = new Vector3d(1, 0, 0);\n        }\n\n        /// <summary>\n        /// Initializes line using point and direction.\n        /// </summary>\n        /// <param name=\"p\">Point on the line.</param>\n        /// <param name=\"v\">Direction vector.</param>\n        public Line3d(Point3d p, Vector3d v)\n        {\n            _point = p.Copy();\n            _dir = v.Normalized;\n        }\n\n        /// <summary>\n        /// Initializes line using two points.\n        /// </summary>\n        /// <param name=\"p1\">First point.</param>\n        /// <param name=\"p2\">Second point.</param>\n        public Line3d(Point3d p1, Point3d p2)\n        {\n            _point = p1.Copy();\n            _dir = new Vector3d(p1, p2).Normalized;\n        }\n        #endregion\n\n        /// <summary>\n        /// Creates copy of the object\n        /// </summary>\n        public Line3d Copy()\n        {\n            return new Line3d(_point, _dir);\n        }\n\n        /// <summary>\n        /// Base point of the line\n        /// </summary>\n        public Point3d Point\n        {\n            get { return _point; }\n            set { _point = value.Copy(); }\n        }\n\n        /// <summary>\n        /// Direction vector of the line\n        /// </summary>\n        public Vector3d Direction\n        {\n            get { return _dir; }\n            set { _dir = value.Copy(); }\n        }\n\n        public bool IsOriented\n        {\n            get { return false; }\n        }\n\n        /// <summary>\n        /// Returns copy of the object\n        /// </summary>\n        public Line3d ToLine\n        {\n            get { return this.Copy(); }\n        }\n\n        #region \"ParallelMethods\"\n        /// <summary>\n        /// Check if two objects are parallel\n        /// </summary>\n        public bool IsParallelTo(ILinearObject obj)\n        {\n            return this.Direction.IsParallelTo(obj.Direction);\n        }\n\n        /// <summary>\n        /// Check if two objects are NOT parallel\n        /// </summary>\n        public bool IsNotParallelTo(ILinearObject obj)\n        {\n            return this.Direction.IsNotParallelTo(obj.Direction);\n        }\n\n        /// <summary>\n        /// Check if two objects are orthogonal\n        /// </summary>\n        public bool IsOrthogonalTo(ILinearObject obj)\n        {\n            return this.Direction.IsOrthogonalTo(obj.Direction);\n        }\n\n        /// <summary>\n        /// Check if two objects are parallel\n        /// </summary>\n        public bool IsParallelTo(IPlanarObject obj)\n        {\n            return this.Direction.IsOrthogonalTo(obj.Normal);\n        }\n\n        /// <summary>\n        /// Check if two objects are NOT parallel\n        /// </summary>\n        public bool IsNotParallelTo(IPlanarObject obj)\n        {\n            return !this.Direction.IsOrthogonalTo(obj.Normal);\n        }\n\n        /// <summary>\n        /// Check if two objects are orthogonal\n        /// </summary>\n        public bool IsOrthogonalTo(IPlanarObject obj)\n        {\n            return this.Direction.IsParallelTo(obj.Normal);\n        }\n\n        /// <summary>\n        /// Check if two objects are coplanar\n        /// </summary>\n        public bool IsCoplanarTo(IPlanarObject obj)\n        {\n            return GeometRi3D._coplanar(this, obj);\n        }\n\n        /// <summary>\n        /// Check if two objects are coplanar\n        /// </summary>\n        public bool IsCoplanarTo(ILinearObject obj)\n        {\n            return GeometRi3D._coplanar(this, obj);\n        }\n        #endregion\n\n        #region \"DistanceTo\"\n        /// <summary>\n        /// Shortest distance between line and point\n        /// </summary>\n        public double DistanceTo(Point3d p)\n        {\n            return p.DistanceTo(this);\n        }\n\n        /// <summary>\n        /// Shortest distance between line and ray\n        /// </summary>\n        public double DistanceTo(Ray3d r)\n        {\n            return r.DistanceTo(this);\n        }\n\n        /// <summary>\n        /// Shortest distance between line and segment\n        /// </summary>\n        public double DistanceTo(Segment3d s)\n        {\n            return s.DistanceTo(this);\n        }\n\n        /// <summary>\n        /// Shortest distance between two lines\n        /// </summary>\n        public virtual double DistanceTo(Line3d l)\n        {\n            Vector3d r1 = this.Point.ToVector;\n            Vector3d r2 = l.Point.ToVector;\n            Vector3d s1 = this.Direction;\n            Vector3d s2 = l.Direction;\n            Vector3d s1CrossS2 = s1.Cross(s2);\n            if (s1CrossS2.Norm > GeometRi3D.Tolerance)\n            {\n                // Crossing lines\n                return Abs((r2 - r1) * s1CrossS2) / s1CrossS2.Norm;\n            }\n            else\n            {\n                // Parallel lines\n                return (r2 - r1).Cross(s1).Norm / s1.Norm;\n            }\n        }\n\n        /// <summary>\n        /// Shortest distance between line and circle (including interior points)\n        /// </summary>\n        public double DistanceTo(Circle3d c)\n        {\n            return c.DistanceTo(this);\n        }\n\n        /// <summary>\n        /// Shortest distance between line and circle (including interior points)\n        /// </summary>\n        /// <param name=\"c\">Target circle</param>\n        /// <param name=\"point_on_line\">Closest point on line</param>\n        /// <param name=\"point_on_circle\">Closest point on circle</param>\n        public double DistanceTo(Circle3d c, out Point3d point_on_line, out Point3d point_on_circle)\n        {\n            return c.DistanceTo(this, out point_on_circle, out point_on_line);\n        }\n        #endregion\n\n\n        /// <summary>\n        /// Point on the perpendicular to the second line (null for parallel lines)\n        /// </summary>\n        public virtual Point3d PerpendicularTo(Line3d l)\n        {\n            Vector3d r1 = this.Point.ToVector;\n            Vector3d r2 = l.Point.ToVector;\n            Vector3d s1 = this.Direction;\n            Vector3d s2 = l.Direction;\n            Vector3d s1CrossS2 = s1.Cross(s2);\n            if (s1CrossS2.Norm > GeometRi3D.Tolerance)\n            {\n                r1 = r2 + (r2 - r1) * s1.Cross(s1CrossS2) / (s1 * s2.Cross(s1CrossS2)) * s2;\n                return r1.ToPoint;\n            }\n            else\n            {\n                // Lineas are parallel\n                // return null\n                return null;\n                //throw new Exception(\"Lines are parallel\");\n            }\n        }\n\n        /// <summary>\n        /// Get intersection of line with other line.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Line3d'.\n        /// </summary>\n        public object IntersectionWith(Line3d l)\n        {\n\n            if (l.IsParallelTo(this) && l.Point.BelongsTo(this))\n            {\n                return this.Copy();\n            }\n\n            Point3d p = l.PerpendicularTo(this);\n            if (p == null)\n            {\n                return null;\n            }\n            else if (p.BelongsTo(l))\n            {\n                return p;\n            }\n            else\n            {\n                return null;\n            }\n        }\n\n        /// <summary>\n        /// Get intersection of line with plane.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Line3d'.\n        /// </summary>\n        public virtual object IntersectionWith(Plane3d s)\n        {\n            return s.IntersectionWith(this);\n        }\n\n        /// <summary>\n        /// Get intersection of line with sphere.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'.\n        /// </summary>\n        public object IntersectionWith(Sphere s)\n        {\n            return s.IntersectionWith(this);\n        }\n\n        /// <summary>\n        /// Get intersection of line with ellipsoid.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'.\n        /// </summary>\n        public object IntersectionWith(Ellipsoid e)\n        {\n            return e.IntersectionWith(this);\n        }\n\n        /// <summary>\n        /// Get intersection of line with ellipse.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'.\n        /// </summary>\n        public object IntersectionWith(Ellipse e)\n        {\n            return e.IntersectionWith(this);\n        }\n\n        /// <summary>\n        /// Get intersection of line with circle.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'.\n        /// </summary>\n        public object IntersectionWith(Circle3d c)\n        {\n            return c.IntersectionWith(this);\n        }\n\n        /// <summary>\n        /// Get intersection of line with segment.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'.\n        /// </summary>\n        public object IntersectionWith(Segment3d s)\n        {\n            return s.IntersectionWith(this);\n        }\n\n        /// <summary>\n        /// Get intersection of line with triangle.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'.\n        /// </summary>\n        public object IntersectionWith(Triangle  t)\n        {\n            return t.IntersectionWith(this);\n        }\n\n        /// <summary>\n        /// Get intersection of line with box.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'.\n        /// </summary>\n        public object IntersectionWith(Box3d b)\n        {\n            return b.IntersectionWith(this);\n        }\n\n        /// <summary>\n        /// Get the orthogonal projection of a line to the plane.\n        /// Return object of type 'Line3d' or 'Point3d'\n        /// </summary>\n        public virtual object ProjectionTo(Plane3d s)\n        {\n            Vector3d n1 = s.Normal;\n            Vector3d n2 = this.Direction.Cross(n1);\n            if (n2.Norm < GeometRi3D.Tolerance)\n            {\n                // Line is perpendicular to the plane\n                return this.Point.ProjectionTo(s);\n            }\n            else\n            {\n                return new Line3d(this.Point.ProjectionTo(s), n1.Cross(n2));\n            }\n        }\n\n        #region \"AngleTo\"\n        /// <summary>\n        /// Angle between two objects in radians (0 &lt; angle &lt; Pi)\n        /// </summary>\n        public double AngleTo(ILinearObject obj)\n        {\n            return GeometRi3D.GetAngle(this, obj);\n        }\n        /// <summary>\n        /// Angle between two objects in degrees (0 &lt; angle &lt; 180)\n        /// </summary>\n        public double AngleToDeg(ILinearObject obj)\n        {\n            return AngleTo(obj) * 180 / PI;\n        }\n\n        /// <summary>\n        /// Angle between two objects in radians (0 &lt; angle &lt; Pi)\n        /// </summary>\n        public double AngleTo(IPlanarObject obj)\n        {\n            return GeometRi3D.GetAngle(this, obj);\n        }\n        /// <summary>\n        /// Angle between two objects in degrees (0 &lt; angle &lt; 180)\n        /// </summary>\n        public double AngleToDeg(IPlanarObject obj)\n        {\n            return AngleTo(obj) * 180 / PI;\n        }\n        #endregion\n\n\n        #region \"TranslateRotateReflect\"\n        /// <summary>\n        /// Translate line by a vector\n        /// </summary>\n        public virtual Line3d Translate(Vector3d v)\n        {\n            Line3d l = this.Copy();\n            l.Point = l.Point.Translate(v);\n            return l;\n        }\n\n        /// <summary>\n        /// Rotate line by a given rotation matrix\n        /// </summary>\n        [System.Obsolete(\"use Rotation object and specify rotation center: this.Rotate(Rotation r, Point3d p)\")]\n        public virtual Line3d Rotate(Matrix3d m)\n        {\n            Line3d l = this.Copy();\n            l.Point = l.Point.Rotate(m);\n            l.Direction = l.Direction.Rotate(m);\n            return l;\n        }\n\n        /// <summary>\n        /// Rotate line by a given rotation matrix around point 'p' as a rotation center\n        /// </summary>\n        [System.Obsolete(\"use Rotation object: this.Rotate(Rotation r, Point3d p)\")]\n        public virtual Line3d Rotate(Matrix3d m, Point3d p)\n        {\n            Line3d l = this.Copy();\n            l.Point = l.Point.Rotate(m, p);\n            l.Direction = l.Direction.Rotate(m);\n            return l;\n        }\n\n        /// <summary>\n        /// Rotate line around point 'p' as a rotation center.\n        /// </summary>\n        public virtual Line3d Rotate(Rotation r, Point3d p)\n        {\n            return new Line3d(this.Point.Rotate(r, p), this.Direction.Rotate(r));\n        }\n\n        /// <summary>\n        /// Reflect line in given point\n        /// </summary>\n        public virtual Line3d ReflectIn(Point3d p)\n        {\n            return new Line3d(this.Point.ReflectIn(p), this.Direction.ReflectIn(p));\n        }\n\n        /// <summary>\n        /// Reflect line in given line\n        /// </summary>\n        public virtual Line3d ReflectIn(Line3d l)\n        {\n            return new Line3d(this.Point.ReflectIn(l), this.Direction.ReflectIn(l));\n        }\n\n        /// <summary>\n        /// Reflect line in given plane\n        /// </summary>\n        public virtual Line3d ReflectIn(Plane3d s)\n        {\n            return new Line3d(this.Point.ReflectIn(s), this.Direction.ReflectIn(s));\n        }\n        #endregion\n\n        /// <summary>\n        /// Determines whether two objects are equal.\n        /// </summary>\n        public override bool Equals(object obj)\n        {\n            if (obj == null || (!object.ReferenceEquals(this.GetType(), obj.GetType())))\n            {\n                return false;\n            }\n            Line3d l = (Line3d)obj;\n\n            if (GeometRi3D.UseAbsoluteTolerance)\n            {\n                return this.Point.BelongsTo(l) && this.Direction.IsParallelTo(l.Direction);\n            }\n            else\n            {\n                double tol = GeometRi3D.Tolerance;\n                if (this.Point == l.Point)\n                {\n                    // Both lines have the same reference point\n                    // Use distance to Origin\n                    GeometRi3D.Tolerance = tol * this.Point.DistanceTo(new Point3d(0,0,0));\n                } else\n                {\n                    // Use max of distance to origin or distance between two points\n                    GeometRi3D.Tolerance = tol * Math.Max(this.Point.DistanceTo(new Point3d(0, 0, 0)), this.Point.DistanceTo(l.Point));\n                }\n                GeometRi3D.UseAbsoluteTolerance = true;\n                bool res1 = this.Point.BelongsTo(l);\n                GeometRi3D.UseAbsoluteTolerance = false;\n                GeometRi3D.Tolerance = tol;\n                bool res2 = this.Direction.IsParallelTo(l.Direction);\n                return res1 && res2;\n            }\n        }\n\n        /// <summary>\n        /// Returns the hashcode for the object.\n        /// </summary>\n        public override int GetHashCode()\n        {\n            return GeometRi3D.HashFunction(_point.GetHashCode(), _dir.GetHashCode());\n        }\n\n        /// <summary>\n        /// String representation of an object in global coordinate system.\n        /// </summary>\n        public override String ToString()\n        {\n            return ToString(Coord3d.GlobalCS);\n        }\n\n        /// <summary>\n        /// String representation of an object in reference coordinate system.\n        /// </summary>\n        public String ToString(Coord3d coord)\n        {\n            System.Text.StringBuilder str = new System.Text.StringBuilder();\n            string nl = System.Environment.NewLine;\n\n            if (coord == null) { coord = Coord3d.GlobalCS; }\n            Point3d P = _point.ConvertTo(coord);\n            Vector3d dir = _dir.ConvertTo(coord);\n\n            str.Append(\"Line:\" + nl);\n            str.Append(string.Format(\"Point  -> ({0,10:g5}, {1,10:g5}, {2,10:g5})\", P.X, P.Y, P.Z) + nl);\n            str.Append(string.Format(\"Direction -> ({0,10:g5}, {1,10:g5}, {2,10:g5})\", dir.X, dir.Y, dir.Z));\n            return str.ToString();\n        }\n\n        // Operators overloads\n        //-----------------------------------------------------------------\n        public static bool operator ==(Line3d l1, Line3d l2)\n        {\n            if (object.ReferenceEquals(l1, null))\n                return object.ReferenceEquals(l2, null);\n            return l1.Equals(l2);\n        }\n        public static bool operator !=(Line3d l1, Line3d l2)\n        {\n            if (object.ReferenceEquals(l1, null))\n                return !object.ReferenceEquals(l2, null);\n            return !l1.Equals(l2);\n        }\n\n    }\n}\n\n\n"
  },
  {
    "path": "GeometRi/Matrix3D.cs",
    "content": "﻿using System;\nusing static System.Math;\n\nnamespace GeometRi\n{\n    /// <summary>\n    /// General 3x3 matrix class.\n    /// </summary>\n#if NET20_OR_GREATER\n    [Serializable]\n#endif\n    public class Matrix3d\n    {\n\n\n        private double[,] val;\n\n        /// <summary>\n        /// Default constructor, intializes zero matrix.\n        /// </summary>\n        public Matrix3d()\n        {\n            val = new double[3, 3];\n            for (int i = 0; i <= 2; i++)\n            {\n                for (int j = 0; j <= 2; j++)\n                {\n                    this.val[i, j] = 0.0;\n                }\n            }\n        }\n        public Matrix3d(Vector3d row1, Vector3d row2, Vector3d row3)\n        {\n            val = new double[3, 3];\n            Row1 = row1;\n            Row2 = row2;\n            Row3 = row3;\n        }\n        public Matrix3d(double[] row1, double[] row2, double[] row3)\n        {\n            val = new double[3, 3];\n            for (int i = 0; i <= 2; i++)\n            {\n                val[0, i] = row1[i];\n                val[1, i] = row2[i];\n                val[2, i] = row3[i];\n            }\n        }\n\n        public static Matrix3d Identity()\n        {\n            Matrix3d I = new Matrix3d();\n            I[0, 0] = 1.0;\n            I[1, 1] = 1.0;\n            I[2, 2] = 1.0;\n            return I;\n        }\n\n        public static Matrix3d DiagonalMatrix(double a11, double a22, double a33)\n        {\n            Matrix3d D = new Matrix3d();\n            D[0, 0] = a11;\n            D[1, 1] = a22;\n            D[2, 2] = a33;\n            return D;\n        }\n\n        /// <summary>\n        /// Creates copy of the object\n        /// </summary>\n        public Matrix3d Copy()\n        {\n            return new Matrix3d(this.Row1, this.Row2, this.Row3);\n        }\n\n        public double this[int i, int j]\n        {\n            get { return this.val[i, j]; }\n            set { this.val[i, j] = value; }\n        }\n\n        public Vector3d Row1\n        {\n            get { return new Vector3d(this.val[0, 0], this.val[0, 1], this.val[0, 2]); }\n            set\n            {\n                this.val[0, 0] = value.X;\n                this.val[0, 1] = value.Y;\n                this.val[0, 2] = value.Z;\n            }\n        }\n        public Vector3d Row2\n        {\n            get { return new Vector3d(this.val[1, 0], this.val[1, 1], this.val[1, 2]); }\n            set\n            {\n                this.val[1, 0] = value.X;\n                this.val[1, 1] = value.Y;\n                this.val[1, 2] = value.Z;\n            }\n        }\n        public Vector3d Row3\n        {\n            get { return new Vector3d(this.val[2, 0], this.val[2, 1], this.val[2, 2]); }\n            set\n            {\n                this.val[2, 0] = value.X;\n                this.val[2, 1] = value.Y;\n                this.val[2, 2] = value.Z;\n            }\n        }\n\n        public Vector3d Column1\n        {\n            get { return new Vector3d(this.val[0, 0], this.val[1, 0], this.val[2, 0]); }\n            set\n            {\n                this.val[0, 0] = value.X;\n                this.val[1, 0] = value.Y;\n                this.val[2, 0] = value.Z;\n            }\n        }\n        public Vector3d Column2\n        {\n            get { return new Vector3d(this.val[0, 1], this.val[1, 1], this.val[2, 1]); }\n            set\n            {\n                this.val[0, 1] = value.X;\n                this.val[1, 1] = value.Y;\n                this.val[2, 1] = value.Z;\n            }\n        }\n        public Vector3d Column3\n        {\n            get { return new Vector3d(this.val[0, 2], this.val[1, 2], this.val[2, 2]); }\n            set\n            {\n                this.val[0, 2] = value.X;\n                this.val[1, 2] = value.Y;\n                this.val[2, 2] = value.Z;\n            }\n        }\n\n        public Vector3d Diagonal\n        {\n            get { return new Vector3d(this.val[0, 0], this.val[1, 1], this.val[2, 2]); }\n            set\n            {\n                this.val[0, 0] = value.X;\n                this.val[1, 1] = value.Y;\n                this.val[2, 2] = value.Z;\n            }\n        }\n\n        /// <summary>\n        /// Determinant of the matrix\n        /// </summary>\n        public double Det\n        {\n            get\n            {\n                double k11 = this.val[2, 2] * this.val[1, 1] - this.val[2, 1] * this.val[1, 2];\n                double k12 = this.val[2, 1] * this.val[0, 2] - this.val[2, 2] * this.val[0, 1];\n                double k13 = this.val[1, 2] * this.val[0, 1] - this.val[1, 1] * this.val[0, 2];\n\n                return this.val[0, 0] * k11 + this.val[1, 0] * k12 + this.val[2, 0] * k13;\n            }\n        }\n\n        /// <summary>\n        /// Trace of the matrix\n        /// </summary>\n        public double Trace\n        {\n            get { return val[0, 0] + val[1, 1] + val[2, 2]; }\n\n        }\n\n        /// <summary>\n        /// Elementwise max norm of the matrix\n        /// </summary>\n        public double MaxNorm\n        {\n            get\n            {\n                double maxval = 0;\n                maxval = Max(Max(Abs(this.val[0, 0]), Abs(this.val[0, 1])), Abs(this.val[0, 2]));\n                maxval = Max(maxval, Max(Max(Abs(this.val[1, 0]), Abs(this.val[1, 1])), Abs(this.val[1, 2])));\n                maxval = Max(maxval, Max(Max(Abs(this.val[2, 0]), Abs(this.val[2, 1])), Abs(this.val[2, 2])));\n                return maxval;\n            }\n        }\n\n        public bool IsZero\n        {\n            get { return this == new Matrix3d(); }\n        }\n\n        public bool IsIdentity\n        {\n            get { return this == Matrix3d.Identity(); }\n        }\n\n        public bool IsOrthogonal\n        {\n            get { return this.Transpose() * this == Matrix3d.Identity(); }\n        }\n\n        public Matrix3d Add(double a)\n        {\n            Matrix3d B = new Matrix3d();\n            for (int i = 0; i <= 2; i++)\n            {\n                for (int j = 0; j <= 2; j++)\n                {\n                    B[i, j] = this.val[i, j] + a;\n                }\n            }\n            return B;\n        }\n        public Matrix3d Add(Matrix3d a)\n        {\n            Matrix3d B = new Matrix3d();\n            for (int i = 0; i <= 2; i++)\n            {\n                for (int j = 0; j <= 2; j++)\n                {\n                    B[i, j] = this.val[i, j] + a[i, j];\n                }\n            }\n            return B;\n        }\n        public Matrix3d Subtract(Matrix3d a)\n        {\n            Matrix3d B = new Matrix3d();\n            for (int i = 0; i <= 2; i++)\n            {\n                for (int j = 0; j <= 2; j++)\n                {\n                    B[i, j] = this.val[i, j] - a[i, j];\n                }\n            }\n            return B;\n        }\n\n        public Matrix3d Mult(double a)\n        {\n            Matrix3d B = new Matrix3d();\n            for (int i = 0; i <= 2; i++)\n            {\n                for (int j = 0; j <= 2; j++)\n                {\n                    B[i, j] = a * this.val[i, j];\n                }\n            }\n            return B;\n        }\n        public Vector3d Mult(Vector3d a)\n        {\n            Vector3d b = new Vector3d(0, 0, 0, a.Coord);\n            b[0] = this.val[0, 0] * a[0] + this.val[0, 1] * a[1] + this.val[0, 2] * a[2];\n            b[1] = this.val[1, 0] * a[0] + this.val[1, 1] * a[1] + this.val[1, 2] * a[2];\n            b[2] = this.val[2, 0] * a[0] + this.val[2, 1] * a[1] + this.val[2, 2] * a[2];\n            return b;\n        }\n        internal Vector3d TransposeMult(Vector3d a)\n        {\n            Vector3d b = new Vector3d(0, 0, 0, a.Coord);\n            b[0] = this.val[0, 0] * a[0] + this.val[1, 0] * a[1] + this.val[2, 0] * a[2];\n            b[1] = this.val[0, 1] * a[0] + this.val[1, 1] * a[1] + this.val[2, 1] * a[2];\n            b[2] = this.val[0, 2] * a[0] + this.val[1, 2] * a[1] + this.val[2, 2] * a[2];\n            return b;\n        }\n        public Point3d Mult(Point3d p)\n        {\n            double x = this.val[0, 0] * p.X + this.val[0, 1] * p.Y + this.val[0, 2] * p.Z;\n            double y = this.val[1, 0] * p.X + this.val[1, 1] * p.Y + this.val[1, 2] * p.Z;\n            double z = this.val[2, 0] * p.X + this.val[2, 1] * p.Y + this.val[2, 2] * p.Z;\n            return new Point3d(x, y, z, p.Coord);\n        }\n        internal Point3d TransposeMult(Point3d p)\n        {\n            double x = this.val[0, 0] * p.X + this.val[1, 0] * p.Y + this.val[2, 0] * p.Z;\n            double y = this.val[0, 1] * p.X + this.val[1, 1] * p.Y + this.val[2, 1] * p.Z;\n            double z = this.val[0, 2] * p.X + this.val[1, 2] * p.Y + this.val[2, 2] * p.Z;\n            return new Point3d(x, y, z, p.Coord);\n        }\n        public Matrix3d Mult(Matrix3d a)\n        {\n            Matrix3d B = new Matrix3d();\n            for (int i = 0; i <= 2; i++)\n            {\n                for (int j = 0; j <= 2; j++)\n                {\n                    for (int k = 0; k <= 2; k++)\n                    {\n                        B[i, j] = B[i, j] + this.val[i, k] * a[k, j];\n                    }\n                }\n            }\n            return B;\n        }\n\n        public Matrix3d Inverse()\n        {\n            Matrix3d B = new Matrix3d();\n\n            double k11 = this.val[2, 2] * this.val[1, 1] - this.val[2, 1] * this.val[1, 2];\n            double k12 = this.val[2, 1] * this.val[0, 2] - this.val[2, 2] * this.val[0, 1];\n            double k13 = this.val[1, 2] * this.val[0, 1] - this.val[1, 1] * this.val[0, 2];\n            double k21 = this.val[2, 0] * this.val[1, 2] - this.val[2, 2] * this.val[1, 0];\n            double k22 = this.val[2, 2] * this.val[0, 0] - this.val[2, 0] * this.val[0, 2];\n            double k23 = this.val[1, 0] * this.val[0, 2] - this.val[1, 2] * this.val[0, 0];\n            double k31 = this.val[2, 1] * this.val[1, 0] - this.val[2, 0] * this.val[1, 1];\n            double k32 = this.val[2, 0] * this.val[0, 1] - this.val[2, 1] * this.val[0, 0];\n            double k33 = this.val[1, 1] * this.val[0, 0] - this.val[1, 0] * this.val[0, 1];\n\n            double det = this.val[0, 0] * k11 + this.val[1, 0] * k12 + this.val[2, 0] * k13;\n\n            if (det != 0.0)\n            {\n                B[0, 0] = k11 / det;\n                B[0, 1] = k12 / det;\n                B[0, 2] = k13 / det;\n\n                B[1, 0] = k21 / det;\n                B[1, 1] = k22 / det;\n                B[1, 2] = k23 / det;\n\n                B[2, 0] = k31 / det;\n                B[2, 1] = k32 / det;\n                B[2, 2] = k33 / det;\n            }\n            else\n            {\n                throw new Exception(\"Matrix is singular\");\n            }\n\n            return B;\n        }\n\n        public Matrix3d Transpose()\n        {\n            Matrix3d T = this.Copy();\n            T[0, 1] = this[1, 0];\n            T[0, 2] = this[2, 0];\n            T[1, 0] = this[0, 1];\n            T[1, 2] = this[2, 1];\n            T[2, 0] = this[0, 2];\n            T[2, 1] = this[1, 2];\n            return T;\n        }\n\n        /// <summary>\n        /// Defines counterclockwise rotation around axis\n        /// </summary>\n        /// <param name=\"axis\">Rotation axis</param>\n        /// <param name=\"alpha\">Angle of rotation (radians)</param>\n        public static Matrix3d RotationMatrix(Vector3d axis, double alpha)\n        {\n            Matrix3d R = new Matrix3d();\n            Vector3d v = axis.Normalized;\n            double c = Cos(alpha);\n            double s = Sin(alpha);\n\n            R[0, 0] = c + Math.Pow(v.X, 2) * (1 - c);\n            R[0, 1] = v.X * v.Y * (1 - c) - v.Z * s;\n            R[0, 2] = v.X * v.Z * (1 - c) + v.Y * s;\n\n            R[1, 0] = v.Y * v.X * (1 - c) + v.Z * s;\n            R[1, 1] = c + Math.Pow(v.Y, 2) * (1 - c);\n            R[1, 2] = v.Y * v.Z * (1 - c) - v.X * s;\n\n            R[2, 0] = v.Z * v.X * (1 - c) - v.Y * s;\n            R[2, 1] = v.Z * v.Y * (1 - c) + v.X * s;\n            R[2, 2] = c + Math.Pow(v.Z, 2) * (1 - c);\n\n            return R;\n        }\n\n        /// <summary>\n        /// Determines whether two objects are equal.\n        /// </summary>\n        public override bool Equals(object obj)\n        {\n            if (obj == null || (!object.ReferenceEquals(this.GetType(), obj.GetType())))\n            {\n                return false;\n            }\n            Matrix3d m = (Matrix3d)obj;\n            if (GeometRi3D.UseAbsoluteTolerance)\n            {\n                return (this - m).MaxNorm < GeometRi3D.Tolerance;\n            }\n            else\n            {\n                return (this - m).MaxNorm / this.MaxNorm < GeometRi3D.Tolerance;\n            }\n\n        }\n\n        /// <summary>\n        /// Returns the hashcode for the object.\n        /// </summary>\n        public override int GetHashCode()\n        {\n            return GeometRi3D.HashFunction(Row1.GetHashCode(), Row2.GetHashCode(), Row3.GetHashCode());\n        }\n\n        /// <summary>\n        /// String representation of an object.\n        /// </summary>\n        public override string ToString()\n        {\n            string str = string.Format(\"Row1 -> ({0,10:g5}, {1,10:g5}, {2,10:g5})\", this.val[0, 0], this.val[0, 1], this.val[0, 2]) + System.Environment.NewLine;\n            str += string.Format(\"Row2 -> ({0,10:g5}, {1,10:g5}, {2,10:g5})\", this.val[1, 0], this.val[1, 1], this.val[1, 2]) + System.Environment.NewLine;\n            str += string.Format(\"Row3 -> ({0,10:g5}, {1,10:g5}, {2,10:g5})\", this.val[2, 0], this.val[2, 1], this.val[2, 2]);\n            return str;\n        }\n\n        // Operators overloads\n        //-----------------------------------------------------------------\n        // \"+\"\n        public static Matrix3d operator +(Matrix3d m, Matrix3d a)\n        {\n            return m.Add(a);\n        }\n        // \"-\"\n        public static Matrix3d operator -(Matrix3d m)\n        {\n            return m.Mult(-1.0);\n        }\n        public static Matrix3d operator -(Matrix3d m, Matrix3d a)\n        {\n            return m.Subtract(a);\n        }\n        // \"*\"\n        public static Matrix3d operator *(Matrix3d m, double a)\n        {\n            return m.Mult(a);\n        }\n        public static Matrix3d operator *(double a, Matrix3d m)\n        {\n            return m.Mult(a);\n        }\n        public static Vector3d operator *(Matrix3d m, Vector3d a)\n        {\n            return m.Mult(a);\n        }\n        public static Point3d operator *(Matrix3d m, Point3d p)\n        {\n            return m.Mult(p);\n        }\n        public static Matrix3d operator *(Matrix3d m, Matrix3d a)\n        {\n            return m.Mult(a);\n        }\n\n        public static bool operator ==(Matrix3d m1, Matrix3d m2)\n        {\n            if (object.ReferenceEquals(m1, null))\n                return object.ReferenceEquals(m2, null);\n            return m1.Equals(m2);\n        }\n        public static bool operator !=(Matrix3d m1, Matrix3d m2)\n        {\n            if (object.ReferenceEquals(m1, null))\n                return !object.ReferenceEquals(m2, null);\n            return !m1.Equals(m2);\n        }\n\n    }\n}\n\n\n"
  },
  {
    "path": "GeometRi/Plane3D.cs",
    "content": "﻿using System;\nusing static System.Math;\n\nnamespace GeometRi\n{\n    /// <summary>\n    /// 3D plane defined by point and a normal vector.\n    /// </summary>\n#if NET20_OR_GREATER\n    [Serializable]\n#endif\n    public class Plane3d : IPlanarObject\n    {\n\n        internal Point3d _point;\n        internal Vector3d _normal;\n        private Coord3d _coord;\n\n        private double _a, _b, _c, _d;\n\n        internal bool HasChanged => _point.HasChanged || _normal.HasChanged;\n        private void CheckFields()\n        {\n            if (HasChanged)\n            {\n                _point = _point.Copy();\n                _normal = _normal.Copy();\n\n                ClearCache();\n            }\n        }\n        private void ClearCache()\n        {\n            _coord = null;\n        }\n\n        #region \"Constructors\"\n        /// <summary>\n        /// Default constructor, initializes XY plane in global cordinate system.\n        /// </summary>\n        public Plane3d()\n        {\n            _point = new Point3d(0, 0, 0);\n            _normal = new Vector3d(0, 0, 1);\n        }\n\n        /// <summary>\n        /// Initializes plane using general equation in 3D space: A*x+B*y+C*z+D=0.\n        /// </summary>\n        /// <param name=\"a\">Parameter \"A\" in general plane equation.</param>\n        /// <param name=\"b\">Parameter \"B\" in general plane equation.</param>\n        /// <param name=\"c\">Parameter \"C\" in general plane equation.</param>\n        /// <param name=\"d\">Parameter \"D\" in general plane equation.</param>\n        /// <param name=\"coord\">Coordinate system in which plane equation is defined (default: Coord3d.GlobalCS).</param>\n        public Plane3d(double a, double b, double c, double d, Coord3d coord = null)\n        {\n            if (coord == null)\n            {\n                coord = Coord3d.GlobalCS;\n            }\n            if (Abs(a) > Abs(b) && Abs(a) > Abs(c))\n            {\n                _point = new Point3d(-d / a, 0, 0, coord);\n            }\n            else if (Abs(b) > Abs(a) && Abs(b) > Abs(c))\n            {\n                _point = new Point3d(0, -d / b, 0, coord);\n            }\n            else\n            {\n                _point = new Point3d(0, 0, -d / c, coord);\n            }\n            _normal = new Vector3d(a, b, c, coord).Normalized;\n        }\n\n        /// <summary>\n        /// Initializes plane using three points.\n        /// </summary>\n        /// <param name=\"p1\">First point.</param>\n        /// <param name=\"p2\">Second point.</param>\n        /// <param name=\"p3\">Third point.</param>\n        public Plane3d(Point3d p1, Point3d p2, Point3d p3)\n        {\n            Vector3d v1 = new Vector3d(p1, p2);\n            Vector3d v2 = new Vector3d(p1, p3);\n            _normal = v1.Cross(v2).Normalized;\n            _point = p1.Copy();\n        }\n\n        /// <summary>\n        /// Initializes plane using point and two vectors lying in the plane.\n        /// </summary>\n        public Plane3d(Point3d p1, Vector3d v1, Vector3d v2)\n        {\n            _normal = v1.Cross(v2).Normalized;\n            _point = p1.Copy();\n        }\n\n        /// <summary>\n        /// Initializes plane using point and normal vector.\n        /// </summary>\n        /// <param name=\"p1\"></param>\n        /// <param name=\"v1\"></param>\n        public Plane3d(Point3d p1, Vector3d v1)\n        {\n            _normal = v1.Normalized;\n            _point = p1.Copy();\n        }\n        #endregion\n\n        /// <summary>\n        /// Creates copy of the object\n        /// </summary>\n        public Plane3d Copy()\n        {\n            return new Plane3d(_point,_normal);\n        }\n\n        /// <summary>\n        /// Point on the plane\n        /// </summary>\n        /// <returns></returns>\n        public Point3d Point\n        {\n            get { return _point; }\n            set { _point = value.Copy(); }\n        }\n\n        /// <summary>\n        /// Normal vector of the plane\n        /// </summary>\n        /// <returns></returns>\n        public Vector3d Normal\n        {\n            get { return _normal; }\n            set { _normal = value.Copy(); }\n        }\n\n        public bool IsOriented\n        {\n            get { return false; }\n        }\n\n        /// <summary>\n        /// Set reference coordinate system for general plane equation\n        /// </summary>\n        public void SetCoord(Coord3d coord = null)\n        {\n            _coord = (coord == null) ? Coord3d.GlobalCS : coord;\n            Vector3d nc = _normal.ConvertTo(_coord);\n            Point3d pc = _point.ConvertTo(_coord);\n            _a = nc.X;\n            _b = nc.Y;\n            _c = nc.Z;\n            _d = -nc.X * pc.X - nc.Y * pc.Y - nc.Z * pc.Z;\n        }\n\n        /// <summary>\n        /// Coefficient A in the general plane equation\n        /// </summary>\n        public double A\n        {\n            get\n            {\n                if (_coord == null) { SetCoord(); }\n                return _a;\n            }\n        }\n\n        /// <summary>\n        /// Coefficient B in the general plane equation\n        /// </summary>\n        public double B\n        {\n            get\n            {\n                if (_coord == null) { SetCoord(); }\n                return _b;\n            }\n        }\n\n        /// <summary>\n        /// Coefficient C in the general plane equation\n        /// </summary>\n        public double C\n        {\n            get\n            {\n                if (_coord == null) { SetCoord(); }\n                return _c;\n            }\n        }\n\n        /// <summary>\n        /// Coefficient D in the general plane equation\n        /// </summary>\n        public double D\n        {\n            get\n            {\n                if (_coord == null) { SetCoord(); }\n                return _d;\n            }\n        }\n\n        /// <summary>\n        /// Returns copy of the object\n        /// </summary>\n        public Plane3d ToPlane\n        {\n            get\n            {\n                return this.Copy();\n            }\n        }\n\n        #region \"ParallelMethods\"\n        /// <summary>\n        /// Check if two objects are parallel\n        /// </summary>\n        public bool IsParallelTo(ILinearObject obj)\n        {\n            return this.Normal.IsOrthogonalTo(obj.Direction);\n        }\n\n        /// <summary>\n        /// Check if two objects are NOT parallel\n        /// </summary>\n        public bool IsNotParallelTo(ILinearObject obj)\n        {\n            return ! this.Normal.IsOrthogonalTo(obj.Direction);\n        }\n\n        /// <summary>\n        /// Check if two objects are orthogonal\n        /// </summary>\n        public bool IsOrthogonalTo(ILinearObject obj)\n        {\n            return this.Normal.IsParallelTo(obj.Direction);\n        }\n\n        /// <summary>\n        /// Check if two objects are parallel\n        /// </summary>\n        public bool IsParallelTo(IPlanarObject obj)\n        {\n            return this.Normal.IsParallelTo(obj.Normal);\n        }\n\n        /// <summary>\n        /// Check if two objects are NOT parallel\n        /// </summary>\n        public bool IsNotParallelTo(IPlanarObject obj)\n        {\n            return this.Normal.IsNotParallelTo(obj.Normal);\n        }\n\n        /// <summary>\n        /// Check if two objects are orthogonal\n        /// </summary>\n        public bool IsOrthogonalTo(IPlanarObject obj)\n        {\n            return this.Normal.IsOrthogonalTo(obj.Normal);\n        }\n\n        /// <summary>\n        /// Check if two objects are coplanar\n        /// </summary>\n        public bool IsCoplanarTo(IPlanarObject obj)\n        {\n            return GeometRi3D._coplanar(this, obj);\n        }\n\n        /// <summary>\n        /// Check if two objects are coplanar\n        /// </summary>\n        public bool IsCoplanarTo(ILinearObject obj)\n        {\n            return GeometRi3D._coplanar(this, obj);\n        }\n        #endregion\n\n        /// <summary>\n        /// Distance from plane to circle\n        /// </summary>\n        public double DistanceTo(Circle3d c)\n        {\n            return c.DistanceTo(this);\n        }\n\n        /// <summary>\n        /// Shortest distance between plane and circle (including interior points)\n        /// </summary>\n        /// <param name=\"c\">Target circle</param>\n        /// <param name=\"point_on_plane\">Closest point on plane</param>\n        /// <param name=\"point_on_circle\">Closest point on circle</param>\n        public double DistanceTo(Circle3d c, out Point3d point_on_plane, out Point3d point_on_circle)\n        {\n            return c.DistanceTo(this, out point_on_circle, out point_on_plane);\n        }\n\n        /// <summary>\n        /// Get intersection of line with plane.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Line3d'.\n        /// </summary>\n        public object IntersectionWith(Line3d l)\n        {\n            Vector3d s1 = l.Direction;\n            Vector3d n2 = this.Normal;\n            if (s1.IsOrthogonalTo(n2))\n            {\n                // Line and plane are parallel\n                if (l.Point.BelongsTo(this))\n                {\n                    // Line lies in the plane\n                    return l;\n                }\n                else\n                {\n                    return null;\n                }\n            }\n            else\n            {\n                // Intersection point\n\n                double d = (this._point - l.Point).Dot(this._normal) / (this._normal * l.Direction);\n                return l.Point.Translate(d * l.Direction);\n            }\n        }\n\n        /// <summary>\n        /// Finds the common intersection of three planes.\n        /// Return 'null' (no common intersection) or object of type 'Point3d', 'Line3d' or 'Plane3d'\n        /// </summary>\n        public object IntersectionWith(Plane3d s2, Plane3d s3)\n        {\n            // Set all planes to global CS\n            this.SetCoord(Coord3d.GlobalCS);\n            s2.SetCoord(Coord3d.GlobalCS);\n            s3.SetCoord(Coord3d.GlobalCS);\n            double det = new Matrix3d(new[] { A, B, C }, new[] { s2.A, s2.B, s2.C }, new [] { s3.A, s3.B, s3.C }).Det;\n            //if (Abs(det) < GeometRi3D.Tolerance)\n            if (Abs(det) < 1e-12)\n                {\n                    if (this.Normal.IsParallelTo(s2.Normal) && this.Normal.IsParallelTo(s3.Normal))\n                {\n                    // Planes are coplanar\n                    if (this.Point.BelongsTo(s2) && this.Point.BelongsTo(s3))\n                    {\n                        return this;\n                    }\n                    else\n                    {\n                        return null;\n                    }\n                }\n                if (this.Normal.IsNotParallelTo(s2.Normal) && this.Normal.IsNotParallelTo(s3.Normal))\n                {\n                    // Planes are not parallel\n                    // Find the intersection (Me,s2) and (Me,s3) and check if it is the same line\n                    Line3d l1 = (Line3d)this.IntersectionWith(s2);\n                    Line3d l2 = (Line3d)this.IntersectionWith(s3);\n                    if (l1 == l2)\n                    {\n                        return l1;\n                    }\n                    else\n                    {\n                        return null;\n                    }\n                }\n\n                // Two planes are parallel, third plane is not\n                return null;\n\n            }\n            else\n            {\n                double x = -new Matrix3d(new[] { D, B, C }, new[] { s2.D, s2.B, s2.C }, new[] { s3.D, s3.B, s3.C }).Det / det;\n                double y = -new Matrix3d(new[] { A, D, C }, new[] { s2.A, s2.D, s2.C }, new[] { s3.A, s3.D, s3.C }).Det / det;\n                double z = -new Matrix3d(new[] { A, B, D }, new[] { s2.A, s2.B, s2.D }, new[] { s3.A, s3.B, s3.D }).Det / det;\n                return new Point3d(x, y, z);\n            }\n        }\n\n        /// <summary>\n        /// Get intersection of two planes.\n        /// Returns 'null' (no intersection) or object of type 'Line3d' or 'Plane3d'.\n        /// </summary>\n        public object IntersectionWith(Plane3d s2)\n        {\n            Vector3d v = this.Normal.Cross(s2.Normal).ConvertToGlobal();\n            if (v.Norm < GeometRi3D.Tolerance)\n            {\n                // Planes are coplanar\n                if (this.Point.BelongsTo(s2))\n                {\n                    return this;\n                }\n                else\n                {\n                    return null;\n                }\n\n            }\n            else\n            {\n                // Find the common point for two planes by intersecting with third plane\n                // (using the 'most orthogonal' plane)\n                // This part needs to be rewritten\n                if (Abs(v.X) >= Abs(v.Y) && Abs(v.X) >= Abs(v.Z))\n                {\n                    Point3d p = (Point3d)Coord3d.GlobalCS.YZ_plane.IntersectionWith(this, s2);\n                    return new Line3d(p, v);\n                }\n                else if (Abs(v.Y) >= Abs(v.X) && Abs(v.Y) >= Abs(v.Z))\n                {\n                    Point3d p = (Point3d)Coord3d.GlobalCS.XZ_plane.IntersectionWith(this, s2);\n                    return new Line3d(p, v);\n                }\n                else\n                {\n                    Point3d p = (Point3d)Coord3d.GlobalCS.XY_plane.IntersectionWith(this, s2);\n                    return new Line3d(p, v);\n                }\n            }\n        }\n\n        /// <summary>\n        /// Get intersection of plane with sphere.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Circle3d'.\n        /// </summary>\n        public object IntersectionWith(Sphere s)\n        {\n            return s.IntersectionWith(this);\n        }\n\n        /// <summary>\n        /// Get intersection of plane with ellispoid.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Ellipse'.\n        /// </summary>\n        public object IntersectionWith(Ellipsoid e)\n        {\n            return e.IntersectionWith(this);\n        }\n\n        /// <summary>\n        /// Intersection of circle with plane.\n        /// Returns 'null' (no intersection) or object of type 'Circle3d', 'Point3d' or 'Segment3d'.\n        /// </summary>\n        public object IntersectionWith(Circle3d c)\n        {\n            return c.IntersectionWith(this);\n        }\n\n        /// <summary>\n        /// Intersection of triangle with plane.\n        /// Returns 'null' (no intersection) or object of type 'Triangle', 'Point3d' or 'Segment3d'.\n        /// </summary>\n        public object IntersectionWith(Triangle t)\n        {\n            return t.IntersectionWith(this);\n        }\n\n        #region \"AngleTo\"\n        /// <summary>\n        /// Angle between two objects in radians (0 &lt; angle &lt; Pi)\n        /// </summary>\n        public double AngleTo(ILinearObject obj)\n        {\n            return GeometRi3D.GetAngle(this, obj);\n        }\n        /// <summary>\n        /// Angle between two objects in degrees (0 &lt; angle &lt; 180)\n        /// </summary>\n        public double AngleToDeg(ILinearObject obj)\n        {\n            return AngleTo(obj) * 180 / PI;\n        }\n\n        /// <summary>\n        /// Angle between two objects in radians (0 &lt; angle &lt; Pi)\n        /// </summary>\n        public double AngleTo(IPlanarObject obj)\n        {\n            return GeometRi3D.GetAngle(this, obj);\n        }\n        /// <summary>\n        /// Angle between two objects in degrees (0 &lt; angle &lt; 180)\n        /// </summary>\n        public double AngleToDeg(IPlanarObject obj)\n        {\n            return AngleTo(obj) * 180 / PI;\n        }\n        #endregion\n\n\n        #region \"TranslateRotateReflect\"\n        /// <summary>\n        /// Translate plane by a vector\n        /// </summary>\n        public Plane3d Translate(Vector3d v)\n        {\n            return new Plane3d(this.Point.Translate(v), this.Normal);\n        }\n\n        /// <summary>\n        /// Rotate plane by a given rotation matrix\n        /// </summary>\n        [System.Obsolete(\"use Rotation object and specify rotation center: this.Rotate(Rotation r, Point3d p)\")]\n        public Plane3d Rotate(Matrix3d m)\n        {\n            return new Plane3d(this.Point.Rotate(m), this.Normal.Rotate(m));\n        }\n\n        /// <summary>\n        /// Rotate plane by a given rotation matrix around point 'p' as a rotation center\n        /// </summary>\n        [System.Obsolete(\"use Rotation object: this.Rotate(Rotation r, Point3d p)\")]\n        public Plane3d Rotate(Matrix3d m, Point3d p)\n        {\n            return new Plane3d(this.Point.Rotate(m, p), this.Normal.Rotate(m));\n        }\n\n        /// <summary>\n        /// Rotate plane around point 'p' as a rotation center\n        /// </summary>\n        public Plane3d Rotate(Rotation r, Point3d p)\n        {\n            return new Plane3d(this.Point.Rotate(r, p), this.Normal.Rotate(r));\n        }\n\n        /// <summary>\n        /// Reflect plane in given point\n        /// </summary>\n        public Plane3d ReflectIn(Point3d p)\n        {\n            return new Plane3d(this.Point.ReflectIn(p), this.Normal.ReflectIn(p));\n        }\n\n        /// <summary>\n        /// Reflect plane in given line\n        /// </summary>\n        public Plane3d ReflectIn(Line3d l)\n        {\n            return new Plane3d(this.Point.ReflectIn(l), this.Normal.ReflectIn(l));\n        }\n\n        /// <summary>\n        /// Reflect plane in given plane\n        /// </summary>\n        public Plane3d ReflectIn(Plane3d s)\n        {\n            return new Plane3d(this.Point.ReflectIn(s), this.Normal.ReflectIn(s));\n        }\n        #endregion\n\n        /// <summary>\n        /// Determines whether two objects are equal.\n        /// </summary>\n        public override bool Equals(object obj)\n        {\n            if (obj == null || (!object.ReferenceEquals(this.GetType(), obj.GetType())))\n            {\n                return false;\n            }\n            Plane3d s = (Plane3d)obj;\n\n            bool isCoplanar;\n            if (this.Normal.IsParallelTo(s.Normal))\n            {\n                if (this.Point.Equals(s.Point))\n                    isCoplanar = true;\n                else\n                {\n                    var v = new Vector3d(this.Point, s.Point).Normalized;\n                    double a = v.Dot(s.Normal.Normalized);\n                    isCoplanar = Abs(a) <= GeometRi3D.DefaultTolerance;\n                }\n            }\n            else\n                isCoplanar = false;\n            return isCoplanar;\n        }\n\n        /// <summary>\n        /// Returns the hashcode for the object.\n        /// </summary>\n        public override int GetHashCode()\n        {\n            return GeometRi3D.HashFunction(_point.GetHashCode(), _normal.GetHashCode());\n        }\n\n        /// <summary>\n        /// String representation of an object in global coordinate system.\n        /// </summary>\n        public override String ToString()\n        {\n            return ToString(Coord3d.GlobalCS);\n        }\n\n        /// <summary>\n        /// String representation of an object in reference coordinate system.\n        /// </summary>\n        public String ToString(Coord3d coord)\n        {\n            System.Text.StringBuilder str = new System.Text.StringBuilder();\n            string nl = System.Environment.NewLine;\n\n            if (coord == null) { coord = Coord3d.GlobalCS; }\n            Point3d P = _point.ConvertTo(coord);\n            Vector3d normal = _normal.ConvertTo(coord);\n\n            str.Append(\"Plane3d:\" + nl);\n            str.Append(string.Format(\"Point  -> ({0,10:g5}, {1,10:g5}, {2,10:g5})\", P.X, P.Y, P.Z) + nl);\n            str.Append(string.Format(\"Normal -> ({0,10:g5}, {1,10:g5}, {2,10:g5})\", normal.X, normal.Y, normal.Z));\n            return str.ToString();\n        }\n\n        // Operators overloads\n        //-----------------------------------------------------------------\n\n        public static bool operator ==(Plane3d s1, Plane3d s2)\n        {\n            if (object.ReferenceEquals(s1, null))\n                return object.ReferenceEquals(s2, null);\n            return s1.Equals(s2);\n        }\n        public static bool operator !=(Plane3d s1, Plane3d s2)\n        {\n            if (object.ReferenceEquals(s1, null))\n                return !object.ReferenceEquals(s2, null);\n            return !s1.Equals(s2);\n        }\n\n    }\n}\n\n\n"
  },
  {
    "path": "GeometRi/Point3D.cs",
    "content": "﻿using System;\nusing static System.Math;\n\nnamespace GeometRi\n{\n    /// <summary>\n    /// Point in 3D space defined in global or local reference frame.\n    /// </summary>\n#if NET20_OR_GREATER\n    [Serializable]\n#endif\n    public class Point3d\n    {\n\n        private double _x;\n        private double _y;\n        private double _z;\n        internal Coord3d _coord;\n\n        #region \"Constructors\"\n        /// <summary>\n        /// Default constructor, initializes zero point.\n        /// </summary>\n        /// <param name=\"coord\">Reference coordinate system (default - Coord3d.GlobalCS).</param>\n        public Point3d(Coord3d coord = null)\n        {\n            _x = 0.0;\n            _y = 0.0;\n            _z = 0.0;\n            _coord = (coord == null) ? Coord3d.GlobalCS : coord;\n        }\n\n        /// <summary>\n        /// Initiaizes point object using coordinates.\n        /// </summary>\n        /// <param name=\"coord\">Reference coordinate system (default - Coord3d.GlobalCS).</param>\n        public Point3d(double x, double y, double z, Coord3d coord = null)\n        {\n            _x = x;\n            _y = y;\n            _z = z;\n            _coord = (coord == null) ? Coord3d.GlobalCS : coord;\n        }\n\n        /// <summary>\n        /// Initiaizes point object using double array.\n        /// </summary>\n        /// <param name=\"coord\">Reference coordinate system (default - Coord3d.GlobalCS).</param>\n        public Point3d(double[] a, Coord3d coord = null)\n        {\n            if (a.GetUpperBound(0) < 2)\n                throw new Exception(\"Point3d: Array size mismatch\");\n            _x = a[0];\n            _y = a[1];\n            _z = a[2];\n            _coord = (coord == null) ? Coord3d.GlobalCS : coord;\n        }\n        #endregion\n\n        /// <summary>\n        /// Creates copy of the object\n        /// </summary>\n        public Point3d Copy()\n        {\n            return new Point3d(_x,_y,_z,_coord);\n        }\n\n        internal bool HasChanged { get; private set; }\n\n        /// <summary>\n        /// X coordinate in reference coordinate system\n        /// </summary>\n        public double X\n        {\n            get { return _x; }\n            set { _x = value; HasChanged = true; }\n        }\n        /// <summary>\n        /// Y coordinate in reference coordinate system\n        /// </summary>\n        public double Y\n        {\n            get { return _y; }\n            set { _y = value; HasChanged = true;}\n        }\n        /// <summary>\n        /// Z coordinate in reference coordinate system\n        /// </summary>\n        public double Z\n        {\n            get { return _z; }\n            set { _z = value; HasChanged = true;}\n        }\n\n        /// <summary>\n        ///  Reference coordinate system\n        /// </summary>\n        public Coord3d Coord\n        {\n            get { return _coord; }\n        }\n\n        /// <summary>\n        /// Radius vector of point (in global coordinate system)\n        /// </summary>\n        public Vector3d ToVector\n        {\n            get { return new Vector3d(this); }\n        }\n\n        /// <summary>\n        /// Convert point to reference coordinate system\n        /// </summary>\n        public Point3d ConvertTo(Coord3d coord)\n        {\n            Point3d p = this.ConvertToGlobal();\n            if (coord == null || object.ReferenceEquals(coord, Coord3d.GlobalCS))\n                return p;\n\n            p = coord.Axes * (p - coord.Origin);\n            p._coord = coord;\n\n            return p;\n        }\n        /// <summary>\n        /// Convert point to global coordinate system\n        /// </summary>\n        /// <returns></returns>\n        public Point3d ConvertToGlobal()\n        {\n            if (_coord == null || object.ReferenceEquals(_coord, Coord3d.GlobalCS))\n            {\n                return this;\n            }\n            else\n            {\n                Point3d p = _coord.Axes.TransposeMult(this);\n                p._coord = Coord3d.GlobalCS;\n\n                return p + _coord.Origin;\n            }\n\n        }\n\n        public Point3d Add(Point3d p)\n        {\n            if ((this._coord != p._coord))\n                p = p.ConvertTo(this._coord);\n            return new Point3d(_x + p._x, _y + p._y, _z + p._z, _coord);\n        }\n        internal Point3d Add(Point3d p, double a, double b)\n        {\n            if ((this._coord != p._coord))\n                p = p.ConvertTo(this._coord);\n            return new Point3d(a * this.X + b * p.X, a * this.Y + b * p.Y, a * this.Z + b * p.Z, _coord);\n        }\n\n        public Point3d Add(Vector3d p)\n        {\n            if ((this._coord != p._coord))\n                p = p.ConvertTo(this._coord);\n            return new Point3d(_x + p.X, _y + p.Y, _z + p.Z, _coord);\n        }\n        public Point3d Subtract(Point3d p)\n        {\n            if ((this._coord != p._coord))\n                p = p.ConvertTo(this._coord);\n            return new Point3d(_x - p._x, _y - p._y, _z - p._z, _coord);\n        }\n        internal Point3d Subtract(Point3d p, double a, double b)\n        {\n            if ((this._coord != p._coord))\n                p = -p._coord.Origin + p.ConvertTo(this._coord);\n            return new Point3d(a * this.X - b * p.X, a * this.Y - b * p.Y, a * this.Z - b * p.Z, _coord);\n        }\n        public Point3d Subtract(Vector3d p)\n        {\n            if ((this._coord != p._coord))\n                p = p.ConvertTo(this._coord);\n            return new Point3d(_x - p.X, _y - p.Y, _z - p.Z, _coord);\n        }\n        internal Point3d Subtract(Vector3d v, double a)\n        {\n            if ((this._coord != v._coord))\n                v = v.ConvertTo(this._coord);\n            return new Point3d(_x - a * v.X, _y - a * v.Y, _z - a * v.Z, _coord);\n        }\n        public Point3d Scale(double a)\n        {\n            return new Point3d(a * _x, a * _y, a * _z, _coord);\n        }\n        internal double Dot(Point3d p)\n        {\n            if ((this._coord != p._coord))\n                p = -p._coord.Origin + p.ConvertTo(this._coord);\n            return this.X * p.X + this.Y * p.Y + this.Z * p.Z;\n        }\n        internal double Dot(Vector3d p)\n        {\n            if ((this._coord != p._coord))\n                p = p.ConvertTo(this._coord);\n            return this.X * p.X + this.Y * p.Y + this.Z * p.Z;\n        }\n        internal Point3d Cross(Point3d v)\n        {\n            if ((this._coord != v._coord))\n                v = -v._coord.Origin + v.ConvertTo(this._coord);\n            double x = this.Y * v.Z - this.Z * v.Y;\n            double y = this.Z * v.X - this.X * v.Z;\n            double z = this.X * v.Y - this.Y * v.X;\n            return new Point3d(x, y, z, _coord); ;\n        }\n\n        //internal (double x, double y, double z) _TSubtract(Point3d p)\n        //{\n        //    if ((this._coord != p._coord))\n        //        p = p.ConvertTo(this._coord);\n        //    return (_x - p._x, _y - p._y, _z - p._z);\n        //}\n\n        //internal double Dot(double x, double y, double z)\n        //{\n        //    return this.X * x + this.Y * y + this.Z * z;\n        //}\n\n        //internal Point3d _TAdd(ValueTuple<double, double, double> p)\n        //{\n        //    return new Point3d(_x + p.Item1, _y + p.Item2, _z + p.Item3, _coord);\n        //}\n\n        #region \"DistanceTo\"\n        /// <summary>\n        /// Returns distance between two points\n        /// </summary>\n        public double DistanceTo(Point3d p)\n        {\n            if ((this._coord != p._coord))\n                p = p.ConvertTo(this._coord);\n            return Sqrt((this._x - p._x) * (this._x - p._x) + (this._y - p._y) * (this._y - p._y) + (this._z - p._z) * (this._z - p._z));\n        }\n\n        /// <summary>\n        /// Returns squared distance between two points\n        /// </summary>\n        public double DistanceSquared(Point3d p)\n        {\n            if ((this._coord != p._coord))\n                p = p.ConvertTo(this._coord);\n            return (this._x - p._x) * (this._x - p._x) + (this._y - p._y) * (this._y - p._y) + (this._z - p._z) * (this._z - p._z);\n        }\n\n        /// <summary>\n        /// Returns shortest distance to the line\n        /// </summary>\n        /// <param name=\"l\"></param>\n        /// <returns></returns>\n        public double DistanceTo(Line3d l)\n        {\n            Vector3d v = new Vector3d(this, l.Point);\n            return v.Cross(l.Direction).Norm;\n        }\n\n        public double DistanceSquared(Line3d l)\n        {\n            Vector3d v = new Vector3d(this, l.Point);\n            return v.Cross(l.Direction).NormSquared;\n        }\n\n        /// <summary>\n        /// Returns shortest distance from point to the plane\n        /// </summary>\n        public double DistanceTo(Plane3d s)\n        {\n            return Math.Abs(s._normal * new Vector3d(s._point, this));\n        }\n\n        public double DistanceSquared(Plane3d s)\n        {\n            double dist = Math.Abs(s._normal * new Vector3d(s._point, this));\n            return dist * dist;\n        }\n\n        /// <summary>\n        /// Returns shortest distance from point to the ray\n        /// </summary>\n        public double DistanceTo(Ray3d r)\n        {\n            double t = r.Direction * new Vector3d(r.Point, this);\n            if (t > 0)\n            {\n                return this.DistanceTo(r.Point + t * r.Direction);\n            }\n            else\n            {\n                return this.DistanceTo(r.Point);\n            }\n        }\n\n        public double DistanceSquared(Ray3d r)\n        {\n            double t = r.Direction * new Vector3d(r.Point, this);\n            if (t > 0)\n            {\n                return this.DistanceSquared(r.Point + t * r.Direction);\n            }\n            else\n            {\n                return this.DistanceSquared(r.Point);\n            }\n        }\n\n        /// <summary>\n        /// Shortest distance from point to the segment\n        /// </summary>\n        public double DistanceTo(Segment3d s)\n        {\n\n            Point3d dir = s.P2 - s.P1;\n            double t0 = dir.Dot(this - s.P1);\n\n            //(double x1, double y1, double z1) = s.P2._TSubtract(s.P1);\n            //(double x2, double y2, double z2) = this._TSubtract(s.P1);\n            //double t0 = x1 * x2 + y1 * y2 + z1 * z2;\n\n            if (t0 <= 0)\n            {\n                return this.DistanceTo(s.P1);\n            }\n\n            double dir_sqr = dir.Dot(dir);\n            //double dir_sqr = x1 * x1 + y1 * y1 + z1 * z1;\n            t0 = t0 / dir_sqr;\n            if (t0 >= 1)\n            {\n                return this.DistanceTo(s.P2);\n            }\n            else\n            {\n                //Point3d p = s.P1._TAdd((t0 * x1, t0  *y1, t0 * z1));\n                //return this.DistanceTo(p);\n                return this.DistanceTo(s.P1 + t0 * dir);\n            }\n        }\n\n        /// <summary>\n        /// Shortest distance from point to the segment\n        /// </summary>\n        public double DistanceTo(Segment3d s, out Point3d closest_point)\n        {\n            // Segment S = P1 + t * (P2-P1)\n            //Vector3d dir = new Vector3d(s.P1, s.P2);\n            //double t0 = dir * new Vector3d(s.P1, this);\n            Point3d dir = s.P2 - s.P1;\n            double t0 = dir.Dot(this - s.P1);\n\n            if (t0 <= 0)\n            {\n                closest_point = s.P1;\n                return this.DistanceTo(s.P1);\n            }\n\n            //double dir_sqr = dir * dir;\n            double dir_sqr = dir.Dot(dir);\n            t0 = t0 / dir_sqr;\n            if (t0 >= 1)\n            {\n                closest_point = s.P2;\n                return this.DistanceTo(s.P2);\n            }\n            else\n            {\n                closest_point = s.P1 + t0 * dir;\n                return this.DistanceTo(closest_point);\n            }\n\n        }\n\n        /// <summary>\n        /// Squared distance from point to the segment\n        /// </summary>\n        public double DistanceSquared(Segment3d s)\n        {\n            // Segment S = P1 + t * (P2-P1)\n            Vector3d dir = new Vector3d(s.P1, s.P2);\n            double t0 = dir * new Vector3d(s.P1, this);\n\n            if (t0 <= 0)\n            {\n                return this.DistanceSquared(s.P1);\n            }\n\n            double dir_sqr = dir * dir;\n            if (dir_sqr > 0)\n            {\n                t0 = t0 / dir_sqr;\n                if (t0 >= 1)\n                {\n                    return this.DistanceSquared(s.P2);\n                }\n                else\n                {\n                    return this.DistanceSquared(s.P1 + t0 * dir);\n                }\n            }\n            else\n            {\n                return this.DistanceSquared(s.P1);\n            }\n        }\n\n        /// <summary>\n        /// Shortest distance between point and sphere (including interior points).\n        /// </summary>\n        public double DistanceTo(Sphere s)\n        {\n            return s.DistanceTo(this);\n        }\n\n        /// <summary>\n        /// Shortest distance from point to circle (including interior points)\n        /// </summary>\n        public double DistanceTo(Circle3d c)\n        {\n            return c.DistanceTo(this);\n        }\n\n        /// <summary>\n        /// Distance from box to point (zero will be returned for point located inside box)\n        /// </summary>\n        public double DistanceTo(Box3d box)\n        {\n            return box.ClosestPoint(this).DistanceTo(this);\n        }\n\n        /// <summary>\n        /// Distance from AABB to point (zero will be returned for point located inside box)\n        /// </summary>\n        public double DistanceTo(AABB box)\n        {\n            return box.ClosestPoint(this).DistanceTo(this);\n        }\n\n        /// <summary>\n        /// Shortest distance from point to triangle (including interior points)\n        /// </summary>\n        public double DistanceTo(Triangle t)\n        {\n            return t.DistanceTo(this);\n        }\n\n        public double DistanceSquared(Triangle t)\n        {\n            return t.DistanceSquared(this);\n        }\n\n        /// <summary>\n        /// Shortest distance from point to triangle (including interior points)\n        /// </summary>\n        public double DistanceTo(Triangle t, out Point3d closest_point)\n        {\n            double dist = t.DistanceTo(this, out closest_point);\n            return dist;\n        }\n\n        #endregion\n\n        /// <summary>\n        /// Closest point on circle (including interior points).\n        /// </summary>\n        public Point3d ClosestPoint(Circle3d c)\n        {\n            return c.ClosestPoint(this);\n        }\n\n        /// <summary>\n        /// Closest point on box (including interior points).\n        /// </summary>\n        public Point3d ClosestPoint(Box3d box)\n        {\n            return box.ClosestPoint(this);\n        }\n\n        /// <summary>\n        /// Closest point on triangle.\n        /// </summary>\n        public Point3d ClosestPoint(Triangle t)\n        {\n            return t.ClosestPoint(this);\n        }\n\n        /// <summary>\n        /// Point on sphere's surface closest to target point \"p\".\n        /// </summary>\n        public Point3d ClosestPoint(Sphere s)\n        {\n            return s.ClosestPoint(this);\n        }\n\n\n        /// <summary>\n        /// Returns orthogonal projection of the point to the plane\n        /// </summary>\n        public Point3d ProjectionTo(Plane3d s)\n        {\n            Vector3d delta = new Vector3d(s._point, this);\n            return this - (s._normal * delta) * s._normal;\n        }\n        /// <summary>\n        /// Returns orthogonal projection of the point to the line\n        /// </summary>\n        public Point3d ProjectionTo(Line3d l)\n        {\n            Vector3d r0 = new Vector3d(this);\n            Vector3d r1 = l.Point.ToVector;\n            Vector3d s = l.Direction;\n            r0 = r1 - ((r1 - r0) * s) / (s * s) * s;\n            return r0.ToPoint;\n        }\n\n        /// <summary>\n        /// Returns orthogonal projection of the point to the surface of the sphere\n        /// </summary>\n        public Point3d ProjectionTo(Sphere s)\n        {\n            Vector3d v = new Vector3d(s.Center, this);\n            return s.Center + s.R * v.Normalized.ToPoint;\n        }\n\n        /// <summary>\n        /// <para>Test if point is located in the epsilon neighborhood of the line.</para>\n        /// <para>Epsilon neighborhood is defined by a GeometRi3D.Tolerance property.</para>\n        /// </summary>\n        public bool BelongsTo(Line3d l)\n        {\n            return this.DistanceTo(l) <= GeometRi3D.Tolerance;\n        }\n\n        /// <summary>\n        /// <para>Test if point is located in the epsilon neighborhood of the ray.</para>\n        /// <para>Epsilon neighborhood is defined by a GeometRi3D.Tolerance property.</para>\n        /// </summary>\n        public bool BelongsTo(Ray3d l)\n        {\n            if (this == l.Point)\n            {\n                return true;\n            }\n\n            if (this.DistanceTo(l.ToLine) <= GeometRi3D.Tolerance)\n            {\n                Point3d proj = this.ProjectionTo(l.ToLine);\n                if (new Vector3d(l.Point, proj).AngleTo(l.Direction) < PI / 4)\n                {\n                    return true;\n                }\n            }\n            return false;\n        }\n\n        /// <summary>\n        /// <para>Test if point is located in the epsilon neighborhood of the plane.</para>\n        /// <para>Epsilon neighborhood is defined by a GeometRi3D.Tolerance property.</para>\n        /// </summary>\n        public bool BelongsTo(Plane3d s)\n        {\n            s.SetCoord(this.Coord);\n            if (GeometRi3D.UseAbsoluteTolerance)\n            {\n                return Abs(s.A * X + s.B * Y + s.C * Z + s.D) / Sqrt(s.A*s.A + s.B * s.B + s.C * s.C) < GeometRi3D.Tolerance;\n            }\n            else\n            {\n                double d = this.DistanceTo(this._coord.Origin);\n                if (d > 0.0)\n                {\n                    return Abs(s.A * X + s.B * Y + s.C * Z + s.D) / Sqrt(s.A * s.A + s.B * s.B + s.C * s.C) / d < GeometRi3D.Tolerance;\n                }\n                else\n                {\n                    return Abs(s.A * X + s.B * Y + s.C * Z + s.D) / Sqrt(s.A * s.A + s.B * s.B + s.C * s.C) < GeometRi3D.Tolerance;\n                }\n            }\n        }\n\n\n\n\n        // =========================================================================\n        #region \"Point location\"\n\n        /// <summary>\n        /// <para>Test if point is located in the epsilon neighborhood of the object.</para>\n        /// <para>Epsilon neighborhood is defined by a GeometRi3D.Tolerance property.</para>\n        /// <para>For relative tolerance tests a fraction of the typical object's dimension is used to define epsilon neighborhood.</para>\n        /// </summary>\n        public bool BelongsTo(FiniteObject obj)\n        {\n            if (obj._PointLocation(this) >= 0) { return true; }\n            return false;\n        }\n\n        /// <summary>\n        /// <para>Test if point is located strictly inside (not in the epsilon neighborhood of the boundary) of the object.</para>\n        /// <para>Epsilon neighborhood is defined by a GeometRi3D.Tolerance property.</para>\n        /// <para>For relative tolerance tests a fraction of the typical object's dimension is used to define epsilon neighborhood.</para>\n        /// </summary>\n        public bool IsInside(FiniteObject obj)\n        {\n            if (obj._PointLocation(this) == 1) { return true; }\n            return false;\n        }\n\n        /// <summary>\n        /// <para>Test if point is located outside of the epsilon neighborhood of the object.</para>\n        /// <para>Epsilon neighborhood is defined by a GeometRi3D.Tolerance property.</para>\n        /// <para>For relative tolerance tests a fraction of the typical object's dimension is used to define epsilon neighborhood.</para>\n        /// </summary>        \n        public bool IsOutside(FiniteObject obj)\n        {\n            if (obj._PointLocation(this) < 0) { return true; }\n            return false;\n        }\n\n        /// <summary>\n        /// <para>Test if point is located in the epsilon neighborhood of the object's boundary.</para>\n        /// <para>Epsilon neighborhood is defined by a GeometRi3D.Tolerance property.</para>\n        /// <para>For relative tolerance tests a fraction of the typical object's dimension is used to define epsilon neighborhood.</para>\n        /// </summary>\n        public bool IsOnBoundary(FiniteObject obj)\n        {\n            if (obj._PointLocation(this) == 0) { return true; }\n            return false;\n        }\n\n        #endregion\n        // =========================================================================\n\n\n\n        #region \"TranslateRotateReflect\"\n        /// <summary>\n        /// Translate point by a vector\n        /// </summary>\n        public Point3d Translate(Vector3d v)\n        {\n            if ((this._coord != v.Coord))\n                v = v.ConvertTo(this._coord);\n            return this + v.ToPoint;\n        }\n\n        /// <summary>\n        /// Rotate point by a given rotation matrix\n        /// </summary>\n        [System.Obsolete(\"use Rotation object and specify rotation center: this.Rotate(Rotation r, Point3d p)\")]\n        public Point3d Rotate(Matrix3d m)\n        {\n            return m * this;\n        }\n\n        /// <summary>\n        /// Rotate point by a given rotation matrix around point 'p' as a rotation center\n        /// </summary>\n        [System.Obsolete(\"use Rotation object: this.Rotate(Rotation r, Point3d p)\")]\n        public Point3d Rotate(Matrix3d m, Point3d p)\n        {\n            if (this._coord != p.Coord)\n                p = p.ConvertTo(this._coord);\n            return m * (this - p) + p;\n        }\n\n        /// <summary>\n        /// Rotate object around origin in object's reference coordinate system.\n        /// </summary>\n        public Point3d Rotate(Rotation r)\n        {\n            if (this._coord != r.Coord) r = r.ConvertTo(this._coord);\n            return r.ToRotationMatrix * this;\n        }\n\n        /// <summary>\n        /// Rotate point around point 'p' as a rotation center.\n        /// </summary>\n        public Point3d Rotate(Rotation r, Point3d p)\n        {\n            if (this._coord != r.Coord) r = r.ConvertTo(this._coord);\n            if (this._coord != p.Coord) p = p.ConvertTo(this._coord);\n            return r.ToRotationMatrix * (this - p) + p;\n        }\n\n        /// <summary>\n        /// Reflect point in given point\n        /// </summary>\n        public Point3d ReflectIn(Point3d p)\n        {\n            if ((this._coord != p.Coord))\n                p = p.ConvertTo(this._coord);\n            Vector3d v = new Vector3d(this, p);\n            return this.Translate(2 * v);\n        }\n\n        /// <summary>\n        /// Reflect point in given line\n        /// </summary>\n        public Point3d ReflectIn(Line3d l)\n        {\n            Vector3d v = new Vector3d(this, this.ProjectionTo(l));\n            return this.Translate(2 * v);\n        }\n\n        /// <summary>\n        /// Reflect point in given plane\n        /// </summary>\n        public Point3d ReflectIn(Plane3d s)\n        {\n            Vector3d v = new Vector3d(this, this.ProjectionTo(s));\n            return this.Translate(2 * v);\n        }\n        #endregion\n\n        /// <summary>\n        /// Check if three points are collinear\n        /// </summary>\n        public static bool CollinearPoints(Point3d A, Point3d B, Point3d C)\n        {\n            Vector3d v1 = new Vector3d(A, B);\n            Vector3d v2 = new Vector3d(A, C);\n            if (v1.Cross(v2).Norm < GeometRi3D.Tolerance)\n            {\n                return true;\n            }\n            else\n            {\n                return false;\n            }\n        }\n\n        /// <summary>\n        /// Determines whether two objects are equal.\n        /// </summary>\n        public override bool Equals(object obj)\n        {\n            if (obj == null || (!object.ReferenceEquals(this.GetType(), obj.GetType())))\n            {\n                return false;\n            }\n            Point3d p = (Point3d)obj;\n\n\n            if (GeometRi3D.UseAbsoluteTolerance)\n            {\n                return this.DistanceSquared(p) < GeometRi3D.Tolerance * GeometRi3D.Tolerance;\n            }\n            else\n            {\n                if (this.DistanceSquared(_coord.Origin) < GeometRi3D.Tolerance * GeometRi3D.Tolerance)\n                {\n                    return this.DistanceSquared(p) < GeometRi3D.Tolerance * GeometRi3D.Tolerance;\n                }\n                else\n                {\n                    return this.DistanceSquared(p) < Math.Pow(GeometRi3D.Tolerance * this.DistanceTo(_coord.Origin), 2);\n                }\n            }\n        }\n\n        /// <summary>\n        /// Returns the hashcode for the object.\n        /// </summary>\n        public override int GetHashCode()\n        {\n            return GeometRi3D.HashFunction(_x.GetHashCode(), _y.GetHashCode(), _z.GetHashCode(), _coord.GetHashCode());\n        }\n\n        /// <summary>\n        /// String representation of an object in global coordinate system.\n        /// </summary>\n        public override String ToString()\n        {\n            return ToString(Coord3d.GlobalCS);\n        }\n\n        /// <summary>\n        /// String representation of an object in reference coordinate system.\n        /// </summary>\n        public String ToString(Coord3d coord)\n        {\n            if (coord == null) { coord = Coord3d.GlobalCS; }\n            Point3d p = this.ConvertTo(coord);\n\n            string str = string.Format(\"Point3d -> ({0,10:g5}, {1,10:g5}, {2,10:g5})\", p.X, p.Y, p.Z) + System.Environment.NewLine;\n            return str;\n        }\n\n\n        // Operators overloads\n        //-----------------------------------------------------------------\n        public static Point3d operator +(Point3d v, Point3d a)\n        {\n            return v.Add(a);\n        }\n        public static Point3d operator +(Point3d v, Vector3d a)\n        {\n            return v.Add(a);\n        }\n        public static Point3d operator -(Point3d v, Point3d a)\n        {\n            return v.Subtract(a);\n        }\n        public static Point3d operator -(Point3d v, Vector3d a)\n        {\n            return v.Subtract(a);\n        }\n        public static Point3d operator -(Point3d v)\n        {\n            return v.Scale(-1.0);\n        }\n        public static Point3d operator *(Point3d v, double a)\n        {\n            return v.Scale(a);\n        }\n        public static Point3d operator *(double a, Point3d v)\n        {\n            return v.Scale(a);\n        }\n        public static Point3d operator /(Point3d v, double a)\n        {\n            return v.Scale(1.0 / a);\n        }\n\n        public static bool operator ==(Point3d p1, Point3d p2)\n        {\n            if (object.ReferenceEquals(p1, null))\n                return object.ReferenceEquals(p2, null);\n            return p1.Equals(p2);\n        }\n        public static bool operator !=(Point3d p1, Point3d p2)\n        {\n            if (object.ReferenceEquals(p1, null))\n                return !object.ReferenceEquals(p2, null);\n            return !p1.Equals(p2);\n        }\n\n    }\n}\n\n\n\n"
  },
  {
    "path": "GeometRi/Quaternion.cs",
    "content": "﻿using System;\nusing static System.Math;\n\nnamespace GeometRi\n{\n    /// <summary>\n    /// Unit quaternion (W + X*i + Y*j + Z*k).\n    /// </summary>\n#if NET20_OR_GREATER\n    [Serializable]\n#endif\n    public class Quaternion\n    {\n\n        private double _w, _x, _y, _z;\n        private Coord3d _coord;\n\n        #region \"Constructors\"\n        /// <summary>\n        /// Default constructor, initializes quaternion with zero rotation (1,0,0,0).\n        /// </summary>\n        /// <param name=\"coord\">Reference coordinate system (default - Coord3d.GlobalCS).</param>\n        public Quaternion(Coord3d coord = null)\n        {\n            _w = 1; _x = 0; _y = 0; _z = 0;\n            _coord = (coord == null) ? Coord3d.GlobalCS : coord;\n        }\n\n        /// <summary>\n        /// Initializes quaternion.\n        /// </summary>\n        /// <param name=\"coord\">Reference coordinate system (default - Coord3d.GlobalCS).</param>\n        public Quaternion(double w, double x, double y, double z, Coord3d coord = null)\n        {\n            _w = w; _x = x; _y = y; _z = z;\n            _coord = (coord == null) ? Coord3d.GlobalCS : coord;\n        }\n\n        /// <summary>\n        /// Initializes quaternion using double array.\n        /// </summary>\n        /// <param name=\"coord\">Reference coordinate system (default - Coord3d.GlobalCS).</param>\n        public Quaternion(double[] q, Coord3d coord = null)\n        {\n            if (q.GetUpperBound(0) < 3)\n                throw new Exception(\"Quaternion: Array size mismatch\");\n            _w = q[0];\n            _x = q[1];\n            _y = q[2];\n            _z = q[3];\n            _coord = (coord == null) ? Coord3d.GlobalCS : coord;\n        }\n\n        /// <summary>\n        /// Initializes quaternion using axis of rotation and angle.\n        /// </summary>\n        public Quaternion(Vector3d axis, double angle)\n        {\n            Vector3d v = axis.Normalized;\n            _w = Cos(angle / 2);\n            _x = v.X * Sin(angle / 2);\n            _y = v.Y * Sin(angle / 2);\n            _z = v.Z * Sin(angle / 2);\n\n            _coord = axis.Coord;\n        }\n\n        /// <summary>\n        /// Initializes quaternion using rotation matrix.\n        /// </summary>\n        /// <param name=\"m\">Rotation matrix.</param>\n        /// <param name=\"coord\">Reference coordinate system (default - Coord3d.GlobalCS).</param>\n        public Quaternion(Matrix3d m, Coord3d coord = null)\n        {\n            if (!m.IsOrthogonal)\n            {\n                throw new Exception(\"Matrix is not orthogonal\");\n            }\n            double tr = m.Trace;\n            if (tr > 0)\n            {\n                _w = 0.5 * Sqrt(tr + 1);\n                _x = -(m[1, 2] - m[2, 1]) / (4 * _w);\n                _y = -(m[2, 0] - m[0, 2]) / (4 * _w);\n                _z = -(m[0, 1] - m[1, 0]) / (4 * _w);\n            } else if (m[0, 0] >= m[1, 1] && m[0, 0] >= m[2, 2])\n            {\n                _x = Sqrt(m[0, 0] - m[1, 1] - m[2, 2] + 1) / 2;\n                _w = -(m[1, 2] - m[2, 1]) / (4 * _x);\n                _y = (m[0, 1] + m[1, 0]) / (4 * _x);\n                _z = (m[0, 2] + m[2, 0]) / (4 * _x);\n            } else if (m[1, 1] >= m[0, 0] && m[1, 1] >= m[2, 2])\n            {\n                _y = Sqrt(m[1, 1] - m[0, 0] - m[2, 2] + 1) / 2;\n                _w = -(m[2, 0] - m[0, 2]) / (4 * _y);\n                _x = (m[0, 1] + m[1, 0]) / (4 * _y);\n                _z = (m[1, 2] + m[2, 1]) / (4 * _y);\n            } else\n            {\n                _z = Sqrt(m[2, 2] - m[0, 0] - m[1, 1] + 1) / 2;\n                _w = -(m[0, 1] - m[1, 0]) / (4 * _z);\n                _x = (m[0, 2] + m[2, 0]) / (4 * _z);\n                _y = (m[1, 2] + m[2, 1]) / (4 * _z);\n            }\n\n            _coord = (coord == null) ? Coord3d.GlobalCS : coord;\n        }\n        #endregion\n\n\n        /// <summary>\n        /// Creates copy of the object\n        /// </summary>\n        public Quaternion Copy()\n        {\n            return new Quaternion(this.W, this.X, this.Y, this.Z, _coord);\n        }\n\n        #region \"Properties\"\n        /// <summary>\n        /// X component in reference coordinate system\n        /// </summary>\n        public double X\n        {\n            get { return _x; }\n            set { _x = value; }\n        }\n\n        /// <summary>\n        /// Y component in reference coordinate system\n        /// </summary>\n        public double Y\n        {\n            get { return _y; }\n            set { _y = value; }\n        }\n\n        /// <summary>\n        /// Z component in reference coordinate system\n        /// </summary>\n        public double Z\n        {\n            get { return _z; }\n            set { _z = value; }\n        }\n\n        /// <summary>\n        /// W component in reference coordinate system\n        /// </summary>\n        public double W\n        {\n            get { return _w; }\n            set { _w = value; }\n        }\n\n        /// <summary>\n        ///  Reference coordinate system\n        /// </summary>\n        public Coord3d Coord\n        {\n            get { return _coord; }\n        }\n\n        /// <summary>\n        /// Norm of a quaternion\n        /// </summary>\n        public double Norm\n        {\n            get { return Sqrt(_w * _w + _x * _x + _y * _y + _z * _z); }\n        }\n\n        /// <summary>\n        /// Square of the norm of a quaternion\n        /// </summary>\n        public double SquareNorm\n        {\n            get { return (_w * _w + _x * _x + _y * _y + _z * _z); }\n        }\n\n        /// <summary>\n        /// Conjugate of a quaternion\n        /// </summary>\n        public Quaternion Conjugate\n        {\n            get {\n                Quaternion qq = this.Copy();\n                qq.X = -this.X;\n                qq.Y = -this.Y;\n                qq.Z = -this.Z;\n                return qq;\n            }\n        }\n\n        /// <summary>\n        /// Get axis of rotation in reference coordinate system.\n        /// </summary>\n        public Vector3d ToAxis\n        {\n            get\n            {\n                this.Normalize();\n                if (GeometRi3D.AlmostEqual(Abs(_w), 1.0))\n                {\n                    // Zero rotation\n                    // For robustness, return any unit vector\n                    return new Vector3d(1, 0, 0, _coord);\n                }\n                else\n                {\n                    double tmp =  1.0 / Sqrt(1 - _w*_w);\n                    return new Vector3d(_x, _y, _z, _coord).Mult(tmp);\n                }\n            }\n        }\n\n        /// <summary>\n        /// Get rotation angle in reference coordinate system.\n        /// </summary>\n        public double ToAngle\n        {\n            get\n            {\n                this.Normalize();\n                if (GeometRi3D.AlmostEqual(Abs(_w),1.0))\n                {\n                    return 0.0;\n                } else\n                {\n                    return 2 * Acos(_w);\n                }\n            }\n        }\n        #endregion\n\n        /// <summary>\n        /// Return normalized quaternion\n        /// </summary>\n        public Quaternion Normalized\n        {\n            get\n            {\n                Quaternion tmp = this.Copy();\n                double tmp_norm = this.Norm;\n                tmp.W = _w / tmp_norm;\n                tmp.X = _x / tmp_norm;\n                tmp.Y = _y / tmp_norm;\n                tmp.Z = _z / tmp_norm;\n                return tmp;\n            }\n        }\n\n        /// <summary>\n        /// Normalize the current quaternion\n        /// </summary>\n        public void Normalize()\n        {\n            double tmp = 1.0 / this.Norm;\n            _w = _w * tmp;\n            _x = _x * tmp;\n            _y = _y * tmp;\n            _z = _z * tmp;\n        }\n\n        public Quaternion Add(Quaternion q)\n        {\n            if ((this._coord != q._coord))\n                q = q.ConvertTo(this._coord);\n\n            Quaternion m = new Quaternion(this.Coord);\n            m.W = _w + q.W;\n            m.X = _x + q.X;\n            m.Y = _y + q.Y;\n            m.Z = _z + q.Z;\n            return m;\n        }\n\n        public Quaternion Subtract(Quaternion q)\n        {\n            if ((this._coord != q._coord))\n                q = q.ConvertTo(this._coord);\n\n            Quaternion m = new Quaternion(this.Coord);\n            m.W = _w - q.W;\n            m.X = _x - q.X;\n            m.Y = _y - q.Y;\n            m.Z = _z - q.Z;\n            return m;\n        }\n\n        public Quaternion Mult (Quaternion q)\n        {\n            if ((this._coord != q._coord))\n                q = q.ConvertTo(this._coord);\n\n            Quaternion m = new Quaternion(this.Coord);\n            m.W = W * q.W - X * q.X - Y * q.Y - Z * q.Z;\n            m.X = W * q.X + X * q.W + Y * q.Z - Z * q.Y;\n            m.Y = W * q.Y - X * q.Z + Y * q.W + Z * q.X;\n            m.Z = W * q.Z + X * q.Y - Y * q.X + Z * q.W;\n\n            return m;\n\n        }\n\n        public Quaternion Scale(double a)\n        {\n            return new Quaternion(_w*a, _x*a, _y*a, _z*a, this.Coord);\n        }\n\n        public Quaternion Inverse()\n        {\n            return this.Conjugate.Scale(1.0 / this.SquareNorm);\n        }\n\n        /// <summary>\n        /// Convert quaternion to global coordinate system.\n        /// </summary>\n        public Quaternion ConvertToGlobal()\n        {\n            if (_coord == null || object.ReferenceEquals(_coord, Coord3d.GlobalCS))\n            {\n                return this.Copy();\n            }\n            else\n            {\n                Vector3d axis = this.ToAxis;\n                double angle = this.ToAngle;\n                axis = axis.ConvertToGlobal();\n                return new Quaternion(axis, angle);\n            }\n        }\n\n        /// <summary>\n        /// Convert quaternion to reference coordinate system.\n        /// </summary>\n        public Quaternion ConvertTo(Coord3d coord)\n        {\n            if (_coord == null || object.ReferenceEquals(_coord, Coord3d.GlobalCS))\n            {\n                return this.Copy();\n            }\n            Vector3d axis = this.ToAxis;\n            double angle = this.ToAngle;\n            axis = axis.ConvertTo(coord);\n            return new Quaternion(axis, angle);\n        }\n\n        /// <summary>\n        /// Returns rotation matrix (in current reference coordinate system).\n        /// </summary>\n        public Matrix3d ToRotationMatrix()\n        {\n            Matrix3d m = new Matrix3d();\n            this.Normalize();\n\n            m[0, 0] = 1 - 2 * (_y * _y + _z * _z);\n            m[0, 1] = 2 * (_x * _y - _w * _z);\n            m[0, 2] = 2 * (_x * _z + _w * _y);\n\n            m[1, 0] = 2 * (_x * _y + _w * _z);\n            m[1, 1] = 1 - 2 * (_x * _x + _z * _z);\n            m[1, 2] = 2 * (_y * _z - _w * _x);\n\n            m[2, 0] = 2 * (_x * _z - _w * _y);\n            m[2, 1] = 2 * (_y * _z + _w * _x);\n            m[2, 2] = 1 - 2 * (_x * _x + _y * _y);\n            return m;\n        }\n\n        /// <summary>\n        /// Spherical linear interpolation of two rotations.\n        /// </summary>\n        /// <param name=\"q1\">Initial rotation</param>\n        /// <param name=\"q2\">Final rotation</param>\n        /// <param name=\"t\">Interpolation parameter within range [0, 1]</param>\n        public static Quaternion SLERP(Quaternion q1, Quaternion q2, double t)\n        {\n            // Algorithm from https://en.wikipedia.org/wiki/Slerp\n\n            Quaternion qq1 = q1.Copy().Normalized;\n            Quaternion qq2 = q2.Copy().Normalized;\n            if (qq2.Coord != qq1.Coord) qq2 = qq2.ConvertTo(qq1.Coord);\n\n            double dot = qq1.W * qq2.W + qq1.X * qq2.X + qq1.Y * qq2.Y + qq1.Z * qq2.Z;\n\n            const double threshold = 0.9995;\n            if (Abs(dot) > threshold)\n            {\n                // Using linear interpolation if two rotations are close\n                Quaternion res = qq1 + t * (qq2 - qq1);\n                res.Normalize();\n                return res;\n            }\n\n            //Make sure to choose shortest path\n            if (dot < 0.0)\n            {\n                qq2 = -qq2;\n                dot = -dot;\n            }\n\n            double theta_0 = Acos(dot);\n            double theta = theta_0 * t;\n\n            qq2 = qq2 - qq1 * dot;\n            qq2.Normalize();\n            return qq1 * Cos(theta) + qq2 * Sin(theta);\n        }\n\n        /// <summary>\n        /// Determines whether two objects are equal.\n        /// </summary>\n        public override bool Equals(object obj)\n        {\n            if (obj == null || (!object.ReferenceEquals(this.GetType(), obj.GetType())))\n            {\n                return false;\n            }\n            Quaternion q = (Quaternion)obj;\n            // No check for absolute tolerance since this is unit quaternion\n            return (this - q).Norm <= GeometRi3D.Tolerance;\n        }\n\n        /// <summary>\n        /// Returns the hashcode for the object.\n        /// </summary>\n        public override int GetHashCode()\n        {\n            return GeometRi3D.HashFunction(_w.GetHashCode(), _x.GetHashCode(), _y.GetHashCode(), _z.GetHashCode());\n        }\n\n        /// <summary>\n        /// String representation of an object in global coordinate system.\n        /// </summary>\n        public override String ToString()\n        {\n            return ToString(Coord3d.GlobalCS);\n        }\n        \n        /// <summary>\n                /// String representation of an object in reference coordinate system.\n                /// </summary>\n        public string ToString(Coord3d coord)\n        {\n            if (coord == null) { coord = Coord3d.GlobalCS; }\n            Quaternion q = this.ConvertTo(coord);\n            return string.Format(\"Quaternion -> ({0,10:g5}, {1,10:g5}, {2,10:g5}, {3,10:g5})\", q.W, q.X, q.Y, q.Z);\n        }\n\n        // Operators overloads\n        //-----------------------------------------------------------------\n        public static Quaternion operator +(Quaternion q1, Quaternion q2)\n        {\n            return q1.Add(q2);\n        }\n\n        public static Quaternion operator -(Quaternion q1, Quaternion q2)\n        {\n            return q1.Subtract(q2);\n        }\n\n        public static Quaternion operator *(Quaternion q1, Quaternion q2)\n        {\n            return q1.Mult(q2);\n        }\n\n        public static Quaternion operator *(Quaternion q1, double a)\n        {\n            return q1.Scale(a);\n        }\n\n        public static Quaternion operator /(Quaternion q1, double a)\n        {\n            return q1.Scale(1.0/a);\n        }\n\n        public static Quaternion operator *(double a, Quaternion q1)\n        {\n            return q1.Scale(a);\n        }\n\n        public static Quaternion operator -(Quaternion q1)\n        {\n            return q1.Scale(-1.0);\n        }\n\n        public static bool operator ==(Quaternion q1, Quaternion q2)\n        {\n            if (object.ReferenceEquals(q1, null))\n                return object.ReferenceEquals(q2, null);\n            return q1.Equals(q2);\n        }\n        public static bool operator !=(Quaternion q1, Quaternion q2)\n        {\n            if (object.ReferenceEquals(q1, null))\n                return !object.ReferenceEquals(q2, null);\n            return !q1.Equals(q2);\n        }\n\n    }\n}\n"
  },
  {
    "path": "GeometRi/Ray3D.cs",
    "content": "﻿using System;\nusing static System.Math;\n\nnamespace GeometRi\n{\n    /// <summary>\n    /// Ray in 3D space defined by point and direction vector.\n    /// </summary>\n#if NET20_OR_GREATER\n    [Serializable]\n#endif\n    public class Ray3d : ILinearObject\n    {\n\n        private Point3d _point;\n        private Vector3d _dir;\n        internal bool HasChanged => _point.HasChanged || _dir.HasChanged;\n\n        /// <summary>\n        /// Default constructor, initializes ray starting from origin and aligned with X-axis (in global coordinate system).\n        /// </summary>\n        public Ray3d()\n        {\n            _point = new Point3d();\n            _dir = new Vector3d(1, 0, 0);\n        }\n\n        /// <summary>\n        /// Initializes ray using starting point and direction.\n        /// </summary>\n        public Ray3d(Point3d p, Vector3d v)\n        {\n            _point = p.Copy();\n            _dir = v.ConvertTo(p.Coord).Normalized;\n        }\n\n        /// <summary>\n        /// Creates copy of the object\n        /// </summary>\n        public Ray3d Copy()\n        {\n            return new Ray3d(_point,_dir);\n        }\n\n        /// <summary>\n        /// Base point of the ray\n        /// </summary>\n        /// <returns></returns>\n        public Point3d Point\n        {\n            get { return _point; }\n            set { _point = value.Copy(); }\n        }\n\n        /// <summary>\n        /// Direction vector of the ray\n        /// </summary>\n        /// <returns></returns>\n        public Vector3d Direction\n        {\n            get { return _dir; }\n            set { _dir = value.Normalized.Copy(); }\n        }\n\n        public bool IsOriented\n        {\n            get { return false; }\n        }\n\n        #region \"ParallelMethods\"\n        /// <summary>\n        /// Check if two objects are parallel\n        /// </summary>\n        public bool IsParallelTo(ILinearObject obj)\n        {\n            return this.Direction.IsParallelTo(obj.Direction);\n        }\n\n        /// <summary>\n        /// Check if two objects are NOT parallel\n        /// </summary>\n        public bool IsNotParallelTo(ILinearObject obj)\n        {\n            return this.Direction.IsNotParallelTo(obj.Direction);\n        }\n\n        /// <summary>\n        /// Check if two objects are orthogonal\n        /// </summary>\n        public bool IsOrthogonalTo(ILinearObject obj)\n        {\n            return this.Direction.IsOrthogonalTo(obj.Direction);\n        }\n\n        /// <summary>\n        /// Check if two objects are parallel\n        /// </summary>\n        public bool IsParallelTo(IPlanarObject obj)\n        {\n            return this.Direction.IsOrthogonalTo(obj.Normal);\n        }\n\n        /// <summary>\n        /// Check if two objects are NOT parallel\n        /// </summary>\n        public bool IsNotParallelTo(IPlanarObject obj)\n        {\n            return !this.Direction.IsOrthogonalTo(obj.Normal);\n        }\n\n        /// <summary>\n        /// Check if two objects are orthogonal\n        /// </summary>\n        public bool IsOrthogonalTo(IPlanarObject obj)\n        {\n            return this.Direction.IsParallelTo(obj.Normal);\n        }\n\n        /// <summary>\n        /// Check if two objects are coplanar\n        /// </summary>\n        public bool IsCoplanarTo(IPlanarObject obj)\n        {\n            return GeometRi3D._coplanar(this, obj);\n        }\n\n        /// <summary>\n        /// Check if two objects are coplanar\n        /// </summary>\n        public bool IsCoplanarTo(ILinearObject obj)\n        {\n            return GeometRi3D._coplanar(this, obj);\n        }\n        #endregion\n\n        /// <summary>\n        /// Convert ray to line\n        /// </summary>\n        public Line3d ToLine\n        {\n            get { return new Line3d(this.Point, this.Direction); }\n        }\n\n        #region \"DistanceTo\"\n        /// <summary>\n        /// Distance from ray to point\n        /// </summary>\n        public double DistanceTo(Point3d p)\n        {\n            return p.DistanceTo(this);\n        }\n\n        /// <summary>\n        /// Shortest distance to a line\n        /// </summary>\n        public double DistanceTo(Line3d l)\n        {\n            Vector3d r1 = this.Point.ToVector;\n            Vector3d r2 = l.Point.ToVector;\n            Vector3d s1 = this.Direction;\n            Vector3d s2 = l.Direction;\n            if (s1.Cross(s2).Norm > GeometRi3D.Tolerance)\n            {\n                // Crossing lines\n                Point3d p = l.PerpendicularTo(new Line3d(this.Point, this.Direction));\n                if (p != null && p.BelongsTo(this))\n                {\n                    return Abs((r2 - r1) * s1.Cross(s2)) / s1.Cross(s2).Norm;\n                }\n                else\n                {\n                    return this.Point.DistanceTo(l);\n                }\n            }\n            else\n            {\n                // Parallel lines\n                return (r2 - r1).Cross(s1).Norm / s1.Norm;\n            }\n        }\n\n        /// <summary>\n        /// Distance to a segment\n        /// </summary>\n        public double DistanceTo(Segment3d s)\n        {\n            return s.DistanceTo(this);\n        }\n\n        /// <summary>\n        /// Distance between two rays\n        /// </summary>\n        public double DistanceTo(Ray3d r)\n        {\n\n            Point3d p1 = this.ToLine.PerpendicularTo(r.ToLine);\n            Point3d p2 = r.ToLine.PerpendicularTo(this.ToLine);\n\n            if (p1 != null && p2 != null && p1.BelongsTo(r) && p2.BelongsTo(this))\n            {\n                return this.ToLine.DistanceTo(r.ToLine);\n            }\n\n            double d1 = double.PositiveInfinity;\n            double d2 = double.PositiveInfinity;\n            bool flag = false;\n\n            if (r.Point.ProjectionTo(this.ToLine).BelongsTo(this))\n            {\n                d1 = r.Point.DistanceTo(this.ToLine);\n                flag = true;\n            }\n            if (this.Point.ProjectionTo(r.ToLine).BelongsTo(r))\n            {\n                d2 = this.Point.DistanceTo(r.ToLine);\n                flag = true;\n            }\n\n            if (flag)\n            {\n                return Min(d1, d2);\n            }\n            else\n            {\n                return this.Point.DistanceTo(r.Point);\n            }\n\n        }\n\n        /// <summary>\n        /// Shortest distance between ray and circle (including interior points)\n        /// </summary>\n        public double DistanceTo(Circle3d c)\n        {\n            return c.DistanceTo(this);\n        }\n\n        /// <summary>\n        /// Shortest distance between ray and circle (including interior points)\n        /// </summary>\n        /// <param name=\"c\">Target circle</param>\n        /// <param name=\"point_on_ray\">Closest point on ray</param>\n        /// <param name=\"point_on_circle\">Closest point on circle</param>\n        public double DistanceTo(Circle3d c, out Point3d point_on_ray, out Point3d point_on_circle)\n        {\n            return c.DistanceTo(this, out point_on_circle, out point_on_ray);\n        }\n        #endregion\n\n\n        /// <summary>\n        /// Point on the perpendicular to the line\n        /// </summary>\n        public Point3d PerpendicularTo(Line3d l)\n        {\n            Vector3d r1 = this.Point.ToVector;\n            Vector3d r2 = l.Point.ToVector;\n            Vector3d s1 = this.Direction;\n            Vector3d s2 = l.Direction;\n            if (s1.Cross(s2).Norm > GeometRi3D.Tolerance)\n            {\n                Point3d p = l.PerpendicularTo(new Line3d(this.Point, this.Direction));\n                if (p != null && p.BelongsTo(this))\n                {\n                    r1 = r2 + (r2 - r1) * s1.Cross(s1.Cross(s2)) / (s1 * s2.Cross(s1.Cross(s2))) * s2;\n                    return r1.ToPoint;\n                }\n                else\n                {\n                    return this.Point.ProjectionTo(l);\n                }\n            }\n            else\n            {\n                throw new Exception(\"Lines are parallel\");\n            }\n        }\n\n        /// <summary>\n        /// Get intersection of ray with plane.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Ray3d'.\n        /// </summary>\n        public object IntersectionWith(Plane3d s)\n        {\n\n            Vector3d r1 = this.Point.ToVector;\n            Vector3d s1 = this.Direction;\n            Vector3d n2 = s.Normal;\n            if (Abs(s1 * n2) < GeometRi3D.Tolerance)\n            {\n                // Ray and plane are parallel\n                if (this.Point.BelongsTo(s))\n                {\n                    // Ray lies in the plane\n                    return this;\n                }\n                else\n                {\n                    return null;\n                }\n            }\n            else\n            {\n                // Intersection point\n                s.SetCoord(r1.Coord);\n                r1 = r1 - ((r1 * n2) + s.D) / (s1 * n2) * s1;\n                if (r1.ToPoint.BelongsTo(this))\n                {\n                    return r1.ToPoint;\n                }\n                else\n                {\n                    return null;\n                }\n            }\n        }\n\n        /// <summary>\n        /// Get intersection of ray with line.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Ray3d'.\n        /// </summary>\n        public object IntersectionWith(Line3d l)\n        {\n\n            if (this.Point.BelongsTo(l) && this.IsParallelTo(l))\n            {\n                return this;\n            }\n\n            object obj = this.ToLine.IntersectionWith(l);\n            if (obj == null)\n            {\n                return null;\n            }\n            else\n            {\n                Point3d p = (Point3d)obj;\n                if (p.BelongsTo(this)) {\n                    return p;\n                }\n                else\n                {\n                    return null;\n                }\n            }\n\n        }\n\n        /// <summary>\n        /// Get intersection of ray with other ray.\n        /// Returns 'null' (no intersection) or object of type 'Point3d', 'Segment3d' or 'Ray3d'.\n        /// </summary>\n        public object IntersectionWith(Ray3d r)\n        {\n\n            if (this == r)\n            {\n                return this;\n            }\n\n            if (this.Point.BelongsTo(r) && this.IsParallelTo(r))\n            {\n                if (r.Point.BelongsTo(this)) {\n                    // Two rays are collinear and opposite\n                    if (this.Point == r. Point)\n                    {\n                        return this.Point;\n                    }\n                    else\n                    {\n                        return new Segment3d(this.Point, r.Point);\n                    }\n                }\n                else\n                {\n                    return this;\n                }\n            }\n\n            if (r.Point.BelongsTo(this) && r.IsParallelTo(this))\n            {\n                return r;\n            }\n\n            object obj = this.ToLine.IntersectionWith(r.ToLine);\n            if (obj == null)\n            {\n                return null;\n            }\n            else\n            {\n                Point3d p = (Point3d)obj;\n                if (p.BelongsTo(this) && p.BelongsTo(r))\n                {\n                    return p;\n                }\n                else\n                {\n                    return null;\n                }\n            }\n\n        }\n\n        /// <summary>\n        /// Get intersection of ray with segment.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'.\n        /// </summary>\n        public object IntersectionWith(Segment3d s)\n        {\n            // Relative tolerance ================================\n            if (!GeometRi3D.UseAbsoluteTolerance)\n            {\n                double tol = GeometRi3D.Tolerance;\n                GeometRi3D.Tolerance = tol * s.Length;\n                GeometRi3D.UseAbsoluteTolerance = true;\n                object result = this.IntersectionWith(s);\n                GeometRi3D.UseAbsoluteTolerance = false;\n                GeometRi3D.Tolerance = tol;\n                return result;\n            }\n  \n            object obj = this.ToLine.IntersectionWith(s);\n            if (obj == null)\n            {\n                return null;\n            }\n            else if (obj.GetType() == typeof(Point3d))\n            {\n                Point3d p = (Point3d)obj;\n                if (p.BelongsTo(this))\n                {\n                    return p;\n                }\n                else\n                {\n                    return null;\n                }\n            }\n            else\n            {\n                Segment3d intersection = (Segment3d)obj;\n                if (intersection.P1.BelongsTo(this) && intersection.P2.BelongsTo(this))\n                {\n                    return intersection;\n                }\n                else if (intersection.P1.BelongsTo(this))\n                {\n                    if (intersection.P1 == this.Point)\n                    {\n                        return this.Point;\n                    }\n                    else\n                    {\n                        return new Segment3d(this.Point, intersection.P1);\n                    }\n                }\n                else if (intersection.P2.BelongsTo(this))\n                {\n                    if (intersection.P2 == this.Point)\n                    {\n                        return this.Point;\n                    }\n                    else\n                    {\n                        return new Segment3d(this.Point, intersection.P2);\n                    }\n                }\n                else\n                {\n                    return null;\n                }\n            }\n\n        }\n\n        /// <summary>\n        /// Get intersection of ray with sphere.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'.\n        /// </summary>\n        public object IntersectionWith(Sphere s)\n        {\n            return s.IntersectionWith(this);\n        }\n\n        /// <summary>\n        /// Get intersection of ray with ellipse.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'.\n        /// </summary>\n        public object IntersectionWith(Ellipse e)\n        {\n            return e.IntersectionWith(this);\n        }\n\n        /// <summary>\n        /// Get intersection of ray with ellipsoid.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'.\n        /// </summary>\n        public object IntersectionWith(Ellipsoid e)\n        {\n            return e.IntersectionWith(this);\n        }\n\n        /// <summary>\n        /// Get intersection of ray with circle.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'.\n        /// </summary>\n        public object IntersectionWith(Circle3d c)\n        {\n            return c.IntersectionWith(this);\n        }\n\n        /// <summary>\n        /// Get intersection of ray with triangle.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'.\n        /// </summary>\n        public object IntersectionWith(Triangle t)\n        {\n            return t.IntersectionWith(this);\n        }\n\n        /// <summary>\n        /// Get intersection of ray with box.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'.\n        /// </summary>\n        public object IntersectionWith(Box3d b)\n        {\n            return b.IntersectionWith(this);\n        }\n\n        /// <summary>\n        /// Get the orthogonal projection of a ray to the plane.\n        /// Return object of type 'Ray3d' or 'Point3d'\n        /// </summary>\n        public object ProjectionTo(Plane3d s)\n        {\n            Vector3d n1 = s.Normal;\n            Vector3d n2 = this.Direction.Cross(n1);\n            if (n2.Norm < GeometRi3D.Tolerance)\n            {\n                // Ray is perpendicular to the plane\n                return this.Point.ProjectionTo(s);\n            }\n            else\n            {\n                return new Ray3d(this.Point.ProjectionTo(s), n1.Cross(n2));\n            }\n        }\n\n        #region \"AngleTo\"\n        /// <summary>\n        /// Angle between two objects in radians (0 &lt; angle &lt; Pi)\n        /// </summary>\n        public double AngleTo(ILinearObject obj)\n        {\n            return GeometRi3D.GetAngle(this, obj);\n        }\n        /// <summary>\n        /// Angle between two objects in degrees (0 &lt; angle &lt; 180)\n        /// </summary>\n        public double AngleToDeg(ILinearObject obj)\n        {\n            return AngleTo(obj) * 180 / PI;\n        }\n\n        /// <summary>\n        /// Angle between two objects in radians (0 &lt; angle &lt; Pi)\n        /// </summary>\n        public double AngleTo(IPlanarObject obj)\n        {\n            return GeometRi3D.GetAngle(this, obj);\n        }\n        /// <summary>\n        /// Angle between two objects in degrees (0 &lt; angle &lt; 180)\n        /// </summary>\n        public double AngleToDeg(IPlanarObject obj)\n        {\n            return AngleTo(obj) * 180 / PI;\n        }\n        #endregion\n\n        #region \"TranslateRotateReflect\"\n        /// <summary>\n        /// Translate ray by a vector\n        /// </summary>\n        public Ray3d Translate(Vector3d v)\n        {\n            Ray3d l = this.Copy();\n            l.Point = l.Point.Translate(v);\n            return l;\n        }\n\n        /// <summary>\n        /// Rotate ray by a given rotation matrix\n        /// </summary>\n        [System.Obsolete(\"use Rotation object and specify rotation center: this.Rotate(Rotation r, Point3d p)\")]\n        public Ray3d Rotate(Matrix3d m)\n        {\n            return new Ray3d(this.Point.Rotate(m), this.Direction.Rotate(m));\n        }\n\n        /// <summary>\n        /// Rotate ray by a given rotation matrix around point 'p' as a rotation center\n        /// </summary>\n        [System.Obsolete(\"use Rotation object: this.Rotate(Rotation r, Point3d p)\")]\n        public Ray3d Rotate(Matrix3d m, Point3d p)\n        {\n            return new Ray3d(this.Point.Rotate(m, p), this.Direction.Rotate(m));\n        }\n\n        /// <summary>\n        /// Rotate ray around point 'p' as a rotation center\n        /// </summary>\n        public Ray3d Rotate(Rotation r, Point3d p)\n        {\n            return new Ray3d(this.Point.Rotate(r, p), this.Direction.Rotate(r));\n        }\n\n        /// <summary>\n        /// Reflect ray in given point\n        /// </summary>\n        public Ray3d ReflectIn(Point3d p)\n        {\n            return new Ray3d(this.Point.ReflectIn(p), this.Direction.ReflectIn(p));\n        }\n\n        /// <summary>\n        /// Reflect ray in given line\n        /// </summary>\n        public Ray3d ReflectIn(Line3d l)\n        {\n            return new Ray3d(this.Point.ReflectIn(l), this.Direction.ReflectIn(l));\n        }\n\n        /// <summary>\n        /// Reflect ray in given plane\n        /// </summary>\n        public Ray3d ReflectIn(Plane3d s)\n        {\n            return new Ray3d(this.Point.ReflectIn(s), this.Direction.ReflectIn(s));\n        }\n        #endregion\n\n        /// <summary>\n        /// Determines whether two objects are equal.\n        /// </summary>\n        public override bool Equals(object obj)\n        {\n            if (obj == null || (!object.ReferenceEquals(this.GetType(), obj.GetType())))\n            {\n                return false;\n            }\n            Ray3d r = (Ray3d)obj;\n\n            if (GeometRi3D.UseAbsoluteTolerance)\n            {\n                return this.Point == r.Point && Abs(this.Direction.Normalized * r.Direction.Normalized - 1) < GeometRi3D.Tolerance;\n            }\n            else\n            {\n                double tol = GeometRi3D.Tolerance;\n                GeometRi3D.Tolerance = tol * this.Point.DistanceTo(this.Point.Coord.Origin);\n                GeometRi3D.UseAbsoluteTolerance = true;\n                bool res1 = this.Point == r.Point;\n                GeometRi3D.UseAbsoluteTolerance = false;\n                GeometRi3D.Tolerance = tol;\n                bool res2 = Abs(this.Direction.Normalized * r.Direction.Normalized - 1) < GeometRi3D.Tolerance;\n                return res1 && res2;\n            }\n        }\n\n        /// <summary>\n        /// Returns the hashcode for the object.\n        /// </summary>\n        public override int GetHashCode()\n        {\n            return GeometRi3D.HashFunction(_point.GetHashCode(), _dir.GetHashCode());\n        }\n\n        /// <summary>\n        /// String representation of an object in global coordinate system.\n        /// </summary>\n        public override String ToString()\n        {\n            return ToString(Coord3d.GlobalCS);\n        }\n\n        /// <summary>\n        /// String representation of an object in reference coordinate system.\n        /// </summary>\n        public String ToString(Coord3d coord)\n        {\n            System.Text.StringBuilder str = new System.Text.StringBuilder();\n            string nl = System.Environment.NewLine;\n\n            if (coord == null) { coord = Coord3d.GlobalCS; }\n            Point3d P = _point.ConvertTo(coord);\n            Vector3d dir = _dir.ConvertTo(coord);\n\n            str.Append(\"Ray:\" + nl);\n            str.Append(string.Format(\"Point  -> ({0,10:g5}, {1,10:g5}, {2,10:g5})\", P.X, P.Y, P.Z) + nl);\n            str.Append(string.Format(\"Direction -> ({0,10:g5}, {1,10:g5}, {2,10:g5})\", dir.X, dir.Y, dir.Z));\n            return str.ToString();\n        }\n\n        // Operators overloads\n        //-----------------------------------------------------------------\n        public static bool operator ==(Ray3d l1, Ray3d l2)\n        {\n            if (object.ReferenceEquals(l1, null))\n                return object.ReferenceEquals(l2, null);\n            return l1.Equals(l2);\n        }\n        public static bool operator !=(Ray3d l1, Ray3d l2)\n        {\n            if (object.ReferenceEquals(l1, null))\n                return !object.ReferenceEquals(l2, null);\n            return !l1.Equals(l2);\n        }\n\n\n    }\n}\n\n\n"
  },
  {
    "path": "GeometRi/Rotation.cs",
    "content": "﻿using System;\nusing static System.Math;\n\n\nnamespace GeometRi\n{\n    /// <summary>\n    /// Rotation in 3D space defined in global or local reference frame (internally represented by rotation matrix).\n    /// </summary>\n#if NET20_OR_GREATER\n    [Serializable]\n#endif\n    public class Rotation\n    {\n        private Matrix3d _r;\n        private Coord3d _coord;\n        private double _angle;\n        private Vector3d _axis;\n        private bool converted_to_axisangle = false;\n\n        #region \"Constructors\"\n        /// <summary>\n        /// Default constructor, initializes identity matrix (zero rotation).\n        /// </summary>\n        public Rotation()\n        {\n            _r = Matrix3d.Identity();\n            _coord = Coord3d.GlobalCS;\n        }\n\n        /// <summary>\n        /// Initializes rotation, equal to the rotation from global CS to 'coord'.\n        /// </summary>\n        public Rotation(Coord3d coord)\n        {\n            if (coord == null)\n            {\n                _r = Matrix3d.Identity();\n            }\n            else\n            {\n                _r = coord.Axes.Transpose();\n            }\n            _coord = Coord3d.GlobalCS;\n        }\n\n        /// <summary>\n        /// Initializes rotation using rotation matrix.\n        /// </summary>\n        /// <param name=\"m\">Rotation matrix.</param>\n        /// <param name=\"coord\">Reference coordinate system (default - Coord3d.GlobalCS).</param>\n        public Rotation(Matrix3d m, Coord3d coord = null)\n        {\n            _r = m.Copy();\n            _coord = (coord == null) ? Coord3d.GlobalCS : coord;\n        }\n\n        /// <summary>\n        /// Initializes rotation using quaternion.\n        /// </summary>\n        /// <param name=\"q\"></param>\n        public Rotation(Quaternion q)\n        {\n            _r = q.ToRotationMatrix();\n            _coord = q.Coord;\n        }\n\n        /// <summary>\n        /// Initializes rotation using axis and angle of rotation.\n        /// </summary>\n        /// <param name=\"axis\">Rotation axis</param>\n        /// <param name=\"alpha\">Angle of rotation (counterclockwise, radians)</param>\n        public Rotation(Vector3d axis, double alpha)\n        {\n            Vector3d v = axis.Normalized;\n            double c = Cos(alpha);\n            double s = Sin(alpha);\n\n            _r = new Matrix3d();\n            _r[0, 0] = c + v.X * v.X * (1 - c);\n            _r[0, 1] = v.X * v.Y * (1 - c) - v.Z * s;\n            _r[0, 2] = v.X * v.Z * (1 - c) + v.Y * s;\n\n            _r[1, 0] = v.Y * v.X * (1 - c) + v.Z * s;\n            _r[1, 1] = c + v.Y * v.Y * (1 - c);\n            _r[1, 2] = v.Y * v.Z * (1 - c) - v.X * s;\n\n            _r[2, 0] = v.Z * v.X * (1 - c) - v.Y * s;\n            _r[2, 1] = v.Z * v.Y * (1 - c) + v.X * s;\n            _r[2, 2] = c + v.Z * v.Z * (1 - c);\n\n            _coord = axis.Coord;\n        }\n\n        //public Rotation(Vector3d axis, double alpha)\n        //{\n        //    Vector3d v = axis.Normalized;\n        //    Matrix3d S = new Matrix3d();\n        //    S[0, 1] = -v.Z;\n        //    S[0, 2] = v.Y;\n        //    S[1, 0] = v.Z;\n        //    S[1, 2] = -v.X;\n        //    S[2, 0] = -v.Y;\n        //    S[2, 1] = v.X;\n\n        //    _rot = Matrix3d.Identity() + Sin(alpha) * S + (1.0 - Cos(alpha)) * S * S;\n        //    _coord = axis.Coord;\n        //}\n        #endregion\n\n        private double this[int i, int j]\n        {\n            get { return this._r[i, j]; }\n            set { this._r[i, j] = value; }\n        }\n\n        /// <summary>\n        /// Random rotation\n        /// </summary>\n        public static Rotation Random()\n        {\n            return new Rotation(Vector3d.Random(), 2 * PI * GeometRi3D.rnd.NextDouble());\n        }\n\n        /// <summary>\n        /// Creates copy of the object\n        /// </summary>\n        public Rotation Copy()\n        {\n            return new Rotation(_r, _coord);\n        }\n\n        /// <summary>\n        /// Returns rotation matrix equivalent to the current rotation.\n        /// </summary>\n        #region \"Properties\"\n        public Matrix3d ToRotationMatrix\n        {\n            get { return this._r; }\n        }\n\n        /// <summary>\n        /// Returns inverse rotation.\n        /// </summary>\n        public Rotation Inverse\n        {\n            get { return new Rotation(this._r.Transpose()); }\n        }\n\n        /// <summary>\n        /// Returns quaternion equivalent to the current rotation.\n        /// </summary>\n        public Quaternion ToQuaternion\n        {\n            get { return new Quaternion(_r, _coord); }\n        }\n\n        /// <summary>\n        /// Returns axis of the rotation (use 'ToAngle' property to get angle of the rotation).\n        /// </summary>\n        public Vector3d ToAxis\n        {\n            get\n            {\n\n                if (converted_to_axisangle)\n                {\n                    return _axis;\n                }\n\n                Quaternion q = this.ToQuaternion;\n                _angle = q.ToAngle;\n                _axis = q.ToAxis;\n                converted_to_axisangle = true;\n                return _axis;\n            }\n        }\n\n        /// <summary>\n        /// Returns angle of the rotation (use 'ToAxis' property to get axis of the rotation).\n        /// </summary>\n        public double ToAngle\n        {\n            get\n            {\n                if (converted_to_axisangle)\n                {\n                    return _angle;\n                }\n                else\n                {\n                    Quaternion q = this.ToQuaternion;\n                    _angle = q.ToAngle;\n                    _axis = q.ToAxis;\n                    converted_to_axisangle = true;\n                    return _angle;\n                }\n            }\n        }\n\n        /// <summary>\n        ///  Reference coordinate system\n        /// </summary>\n        public Coord3d Coord\n        {\n            get { return _coord; }\n        }\n        #endregion\n\n        /// <summary>\n        /// Creates rotation object by composing three elemental rotations, i.e. rotations about the axes of a coordinate system.\n        /// <para>Both proper Euler angles (\"xyx\", \"zxz\", etc.) or Tait–Bryan angles (\"xyz\", \"yzx\") are allowed.</para>\n        /// Extrinsic rotations (rotations in fixed frame) should be written in lower case (\"xyz\", zxz\", etc.).\n        /// <para>Intrinsic rotations (rotations in moving frame) should be written in upper case (\"XYZ\", \"ZXZ\", etc.).</para>\n        /// </summary>\n        /// <param name=\"alpha\">First rotation angle.</param>\n        /// <param name=\"beta\">Second rotation angle.</param>\n        /// <param name=\"gamma\">Third rotation angle.</param>\n        /// <param name=\"RotationOrder\">String, representing rotation axes in the form \"xyz\" (extrinsic rotations, fixed frame) or \"XYZ\" (intrinsic rotations, moving frame).</param>\n        /// <param name=\"coord\">Reference coordinate system, default - Coord3d.GlobalCS.</param>\n        /// <returns></returns>\n        public static Rotation FromEulerAngles(double alpha, double beta, double gamma, string RotationOrder, Coord3d coord = null)\n        {\n            if (string.IsNullOrEmpty(RotationOrder) || RotationOrder.Length < 3)\n            {\n                throw new ArgumentException(\"Invalid parameter: RotationOrder\");\n            }\n\n            coord = (coord == null) ? Coord3d.GlobalCS : coord;\n            Vector3d v1 = CharToVector(RotationOrder[0], coord);\n            Vector3d v2 = CharToVector(RotationOrder[1], coord);\n            Vector3d v3 = CharToVector(RotationOrder[2], coord);\n\n            Rotation r1 = new Rotation(v1, alpha);\n            Rotation r2 = new Rotation(v2, beta);\n            Rotation r3 = new Rotation(v3, gamma);\n\n            if (RotationOrder[0] == 'x' || RotationOrder[0] == 'y' || RotationOrder[0] == 'z')\n            {\n                // Rotation in fixed frame\n                return r3 * r2 * r1;\n            }\n            else\n            {\n                // Rotation in moving frame\n                return r1 * r2 * r3;\n            }\n        }\n        private static Vector3d CharToVector(char c, Coord3d coord)\n        {\n            if (c == 'x' || c == 'X') return new Vector3d(1, 0, 0, coord);\n            if (c == 'y' || c == 'Y') return new Vector3d(0, 1, 0, coord);\n            if (c == 'z' || c == 'Z') return new Vector3d(0, 0, 1, coord);\n\n            throw new ArgumentException(\"Invalid parameter: RotationOrder\");\n        }\n\n        /// <summary>\n        /// Factor a rotation matrix as product of three elemental rotations, i.e. rotations about the axes of a coordinate system.\n        /// <para>Both proper Euler angles (\"xyx\", \"zxz\", etc.) or Tait–Bryan angles (\"xyz\", \"yzx\") are allowed.</para>\n        /// Extrinsic rotations (rotations in fixed frame) should be written in lower case (\"xyz\", zxz\", etc.).\n        /// <para>Intrinsic rotations (rotations in moving frame) should be written in upper case (\"XYZ\", \"ZXZ\", etc.).</para>\n        /// Note that such factorization generally is not unique!\n        /// </summary>\n        /// <param name=\"RotationOrder\">String, representing rotation axes in the form \"xyz\" (extrinsic rotations, fixed frame) or \"XYZ\" (intrinsic rotations, moving frame).</param>\n        /// <param name=\"coord\">Reference coordinate system, default - Coord3d.GlobalCS.</param>\n        /// <returns>Double array with first, second and third rotation angles</returns>\n        public double[] ToEulerAngles(string RotationOrder, Coord3d coord = null)\n        {\n            if (string.IsNullOrEmpty(RotationOrder) || RotationOrder.Length < 3)\n            {\n                throw new ArgumentException(\"Invalid parameter: RotationOrder\");\n            }\n\n            coord = (coord == null) ? Coord3d.GlobalCS : coord;\n            Rotation r = this.ConvertTo(coord);\n\n            // Portions of the code were derived from article\n            // https://www.geometrictools.com/Documentation/EulerAngles.pdf\n            // published under Boost license\n            //============================================================================\n            // Boost Software License - Version 1.0 - August 17th, 2003\n\n            // Permission is hereby granted, free of charge, to any person or organization\n            //obtaining a copy of the software and accompanying documentation covered by\n            //this license(the \"Software\") to use, reproduce, display, distribute,\n            //execute, and transmit the Software, and to prepare derivative works of the\n            //Software, and to permit third - parties to whom the Software is furnished to\n            //do so, all subject to the following:\n\n            // The copyright notices in the Software and this entire statement, including\n            //the above license grant, this restriction and the following disclaimer,\n            //must be included in all copies of the Software, in whole or in part, and\n            //all derivative works of the Software, unless such copies or derivative\n            //works are solely in the form of machine-executable object code generated by\n            //a source language processor.\n\n            // THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n            //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n            //FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON - INFRINGEMENT.IN NO EVENT\n            //SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\n            //FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\n            //ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n            //DEALINGS IN THE SOFTWARE.\n            //============================================================================\n\n            double ax, ay, az;\n            if (RotationOrder == \"XYZ\" || RotationOrder == \"zyx\")\n            {\n                if (GeometRi3D.Smaller(r[0,2],1))\n                {\n                    if (GeometRi3D.Greater(r[0, 2], -1))\n                    {\n                        ay = Asin(r[0, 2]);\n                        ax = Atan2(-r[1, 2], r[2, 2]);\n                        az = Atan2(-r[0, 1], r[0, 0]);\n                    }\n                    else\n                    {\n                        ay = -PI / 2.0;\n                        ax = -Atan2(r[1, 0], r[1, 1]);\n                        az = 0;\n                    }\n                }\n                else\n                {\n                    ay = PI / 2.0;\n                    ax = Atan2(r[1, 0], r[1, 1]);\n                    az = 0;\n                }\n                if (RotationOrder == \"XYZ\")\n                {\n                    return new[] { ax, ay, az };\n                }\n                else\n                {\n                    return new[] { az, ay, ax };\n                }\n            }\n\n            if (RotationOrder == \"XZY\" || RotationOrder == \"yzx\")\n            {\n                if (GeometRi3D.Smaller(r[0, 1], 1))\n                {\n                    if (GeometRi3D.Greater(r[0, 1], -1))\n                    {\n                        az = Asin(-r[0, 1]);\n                        ax = Atan2(r[2, 1], r[1, 1]);\n                        ay = Atan2(r[0, 2], r[0, 0]);\n                    }\n                    else\n                    {\n                        az = PI / 2.0;\n                        ax = -Atan2(-r[2, 0], r[2, 2]);\n                        ay = 0;\n                    }\n                }\n                else\n                {\n                    az = -PI / 2.0;\n                    ax = Atan2(-r[2, 0], r[2, 2]);\n                    ay = 0;\n                }\n                if (RotationOrder == \"XZY\")\n                {\n                    return new[] { ax, az, ay };\n                }\n                else\n                {\n                    return new[] { ay, az, ax };\n                }\n            }\n\n            if (RotationOrder == \"YXZ\" || RotationOrder == \"zxy\")\n            {\n                if (GeometRi3D.Smaller(r[1, 2], 1))\n                {\n                    if (GeometRi3D.Greater(r[1, 2], -1))\n                    {\n                        ax = Asin(-r[1, 2]);\n                        ay = Atan2(r[0, 2], r[2, 2]);\n                        az = Atan2(r[1, 0], r[1, 1]);\n                    }\n                    else\n                    {\n                        ax = PI / 2.0;\n                        ay = -Atan2(-r[0, 2], r[0, 0]);\n                        az = 0;\n                    }\n                }\n                else\n                {\n                    ax = -PI / 2.0;\n                    ay = Atan2(-r[0, 1], r[0, 0]);\n                    az = 0;\n                }\n                if (RotationOrder == \"YXZ\")\n                {\n                    return new[] { ay, ax, az };\n                }\n                else\n                {\n                    return new[] { az, ax, ay };\n                }\n            }\n\n            if (RotationOrder == \"YZX\" || RotationOrder == \"xzy\")\n            {\n                if (GeometRi3D.Smaller(r[1, 0], 1))\n                {\n                    if (GeometRi3D.Greater(r[1, 0], -1))\n                    {\n                        az = Asin(r[1, 0]);\n                        ay = Atan2(-r[2, 0], r[0, 0]);\n                        ax = Atan2(-r[1, 2], r[1, 1]);\n                    }\n                    else\n                    {\n                        az = -PI / 2.0;\n                        ay = -Atan2(r[2, 1], r[2, 2]);\n                        ax = 0;\n                    }\n                }\n                else\n                {\n                    az = PI / 2.0;\n                    ay = Atan2(r[2, 1], r[2, 2]);\n                    ax = 0;\n                }\n                if (RotationOrder == \"YZX\")\n                {\n                    return new[] { ay, az, ax };\n                }\n                else\n                {\n                    return new[] { ax, az, ay };\n                }\n            }\n\n            if (RotationOrder == \"ZXY\" || RotationOrder == \"yxz\")\n            {\n                if (GeometRi3D.Smaller(r[2, 1], 1))\n                {\n                    if (GeometRi3D.Greater(r[2, 1], -1))\n                    {\n                        ax = Asin(r[2, 1]);\n                        az = Atan2(-r[0, 1], r[1, 1]);\n                        ay = Atan2(-r[2, 0], r[2, 2]);\n                    }\n                    else\n                    {\n                        ax = -PI / 2.0;\n                        az = -Atan2(r[0, 2], r[0, 0]);\n                        ay = 0;\n                    }\n                }\n                else\n                {\n                    ax = PI / 2.0;\n                    az = Atan2(r[0, 2], r[0, 0]);\n                    ay = 0;\n                }\n                if (RotationOrder == \"ZXY\")\n                {\n                    return new[] { az, ax, ay };\n                }\n                else\n                {\n                    return new[] { ay, ax, az };\n                }\n            }\n\n            if (RotationOrder == \"ZYX\" || RotationOrder == \"xyz\")\n            {\n                if (GeometRi3D.Smaller(r[2, 0], 1))\n                {\n                    if (GeometRi3D.Greater(r[2, 0], -1))\n                    {\n                        ay = Asin(-r[2, 0]);\n                        az = Atan2(r[1, 0], r[0, 0]);\n                        ax = Atan2(r[2, 1], r[2, 2]);\n                    }\n                    else\n                    {\n                        ay = PI / 2.0;\n                        az = -Atan2(-r[1, 2], r[1, 1]);\n                        ax = 0;\n                    }\n                }\n                else\n                {\n                    ay = -PI / 2.0;\n                    az = Atan2(-r[1, 2], r[1, 1]);\n                    ax = 0;\n                }\n                if (RotationOrder == \"ZYX\")\n                {\n                    return new[] { az, ay, ax };\n                }\n                else\n                {\n                    return new[] { ax, ay, az };\n                }\n            }\n\n\n            double a1, a2, a3;\n            if (RotationOrder == \"XYX\" || RotationOrder == \"xyx\")\n            {\n                if (GeometRi3D.Smaller(r[0, 0], 1))\n                {\n                    if (GeometRi3D.Greater(r[0, 0], -1))\n                    {\n                        a2 = Acos(r[0, 0]);\n                        a1 = Atan2(r[1, 0], -r[2, 0]);\n                        a3 = Atan2(r[0, 1], r[0, 2]);\n                    }\n                    else\n                    {\n                        a2 = PI;\n                        a1 = -Atan2(-r[1, 2], r[1, 1]);\n                        a3 = 0;\n                    }\n                }\n                else\n                {\n                    a2 = 0;\n                    a1 = Atan2(-r[1, 2], r[1, 1]);\n                    a3 = 0;\n                }\n                if (RotationOrder == \"XYX\")\n                {\n                    return new[] { a1, a2, a3 };\n                }\n                else\n                {\n                    return new[] { a3, a2, a1 };\n                }\n            }\n\n            if (RotationOrder == \"XZX\" || RotationOrder == \"xzx\")\n            {\n                if (GeometRi3D.Smaller(r[0, 0], 1))\n                {\n                    if (GeometRi3D.Greater(r[0, 0], -1))\n                    {\n                        a2 = Acos(r[0, 0]);\n                        a1 = Atan2(r[2, 0], r[1, 0]);\n                        a3 = Atan2(r[0, 2], -r[0, 1]);\n                    }\n                    else\n                    {\n                        a2 = PI;\n                        a1 = -Atan2(-r[2, 1], r[2, 2]);\n                        a3 = 0;\n                    }\n                }\n                else\n                {\n                    a2 = 0;\n                    a1 = Atan2(r[2, 1], r[2, 2]);\n                    a3 = 0;\n                }\n                if (RotationOrder == \"XZX\")\n                {\n                    return new[] { a1, a2, a3 };\n                }\n                else\n                {\n                    return new[] { a3, a2, a1 };\n                }\n            }\n\n            if (RotationOrder == \"YXY\" || RotationOrder == \"yxy\")\n            {\n                if (GeometRi3D.Smaller(r[1, 1], 1))\n                {\n                    if (GeometRi3D.Greater(r[1, 1], -1))\n                    {\n                        a2 = Acos(r[1, 1]);\n                        a1 = Atan2(r[0, 1], r[2, 1]);\n                        a3 = Atan2(r[1, 0], -r[1, 2]);\n                    }\n                    else\n                    {\n                        a2 = PI;\n                        a1 = -Atan2(r[0, 2], r[0, 0]);\n                        a3 = 0;\n                    }\n                }\n                else\n                {\n                    a2 = 0;\n                    a1 = Atan2(r[0, 2], r[0, 0]);\n                    a3 = 0;\n                }\n                if (RotationOrder == \"YXY\")\n                {\n                    return new[] { a1, a2, a3 };\n                }\n                else\n                {\n                    return new[] { a3, a2, a1 };\n                }\n            }\n\n            if (RotationOrder == \"YZY\" || RotationOrder == \"yzy\")\n            {\n                if (GeometRi3D.Smaller(r[1, 1], 1))\n                {\n                    if (GeometRi3D.Greater(r[1, 1], -1))\n                    {\n                        a2 = Acos(r[1, 1]);\n                        a1 = Atan2(r[2, 1], -r[0, 1]);\n                        a3 = Atan2(r[1, 2], r[1, 0]);\n                    }\n                    else\n                    {\n                        a2 = PI;\n                        a1 = -Atan2(-r[2, 0], r[2, 2]);\n                        a3 = 0;\n                    }\n                }\n                else\n                {\n                    a2 = 0;\n                    a1 = Atan2(-r[2, 0], r[2, 2]);\n                    a3 = 0;\n                }\n                if (RotationOrder == \"YZY\")\n                {\n                    return new[] { a1, a2, a3 };\n                }\n                else\n                {\n                    return new[] { a3, a2, a1 };\n                }\n            }\n\n            if (RotationOrder == \"ZXZ\" || RotationOrder == \"zxz\")\n            {\n                if (GeometRi3D.Smaller(r[2, 2], 1))\n                {\n                    if (GeometRi3D.Greater(r[2, 2], -1))\n                    {\n                        a2 = Acos(r[2, 2]);\n                        a1 = Atan2(r[0, 2], -r[1, 2]);\n                        a3 = Atan2(r[2, 0], r[2, 1]);\n                    }\n                    else\n                    {\n                        a2 = PI;\n                        a1 = -Atan2(-r[0, 1], r[0, 0]);\n                        a3 = 0;\n                    }\n                }\n                else\n                {\n                    a2 = 0;\n                    a1 = Atan2(-r[0, 1], r[0, 0]);\n                    a3 = 0;\n                }\n                if (RotationOrder == \"ZXZ\")\n                {\n                    return new[] { a1, a2, a3 };\n                }\n                else\n                {\n                    return new[] { a3, a2, a1 };\n                }\n            }\n\n            if (RotationOrder == \"ZYZ\" || RotationOrder == \"zyz\")\n            {\n                if (GeometRi3D.Smaller(r[2, 2], 1))\n                {\n                    if (GeometRi3D.Greater(r[2, 2], -1))\n                    {\n                        a2 = Acos(r[2, 2]);\n                        a1 = Atan2(r[1, 2], r[0, 2]);\n                        a3 = Atan2(r[2, 1], -r[2, 0]);\n                    }\n                    else\n                    {\n                        a2 = PI;\n                        a1 = -Atan2(r[1, 0], r[1, 1]);\n                        a3 = 0;\n                    }\n                }\n                else\n                {\n                    a2 = 0;\n                    a1 = Atan2(r[1, 0], r[1, 1]);\n                    a3 = 0;\n                }\n                if (RotationOrder == \"ZYZ\")\n                {\n                    return new[] { a1, a2, a3 };\n                }\n                else\n                {\n                    return new[] { a3, a2, a1 };\n                }\n            }\n\n            throw new ArgumentException(\"Invalid parameter: RotationOrder\");\n        }\n\n        /// <summary>\n        /// Spherical linear interpolation of two rotations.\n        /// </summary>\n        /// <param name=\"r1\">Initial rotation</param>\n        /// <param name=\"r2\">Final rotation</param>\n        /// <param name=\"t\">Interpolation parameter within range [0, 1]</param>\n        public static Rotation SLERP(Rotation r1, Rotation r2, double t)\n        {\n            return new Rotation(Quaternion.SLERP(r1.ToQuaternion, r2.ToQuaternion, t));\n        }\n\n        /// <summary>\n        /// Combine two rotations.\n        /// </summary>\n        public Rotation Mult(Rotation r)\n        {\n            Matrix3d m = this.ToRotationMatrix * r.ConvertTo(this.Coord).ToRotationMatrix;\n            return new Rotation(m, this.Coord);\n        }\n\n        /// <summary>\n        /// Multiply rotation matrix by vector.\n        /// <para>The rotation matrix is first transformed into reference coordinate system of vector.</para>\n        /// </summary>\n        public Vector3d Mult(Vector3d v)\n        {\n            return this.ConvertTo(v.Coord).ToRotationMatrix * v;\n        }\n\n        /// <summary>\n        /// Multiply rotation matrix by point.\n        /// <para>The rotation matrix is first transformed into reference coordinate system of point.</para>\n        /// </summary>\n        public Point3d Mult(Point3d p)\n        {\n            return this.ConvertTo(p.Coord).ToRotationMatrix * p;\n        }\n\n        /// <summary>\n        /// Convert rotation object to global coordinate system.\n        /// </summary>\n        public Rotation ConvertToGlobal()\n        {\n            if (_coord == null || object.ReferenceEquals(_coord, Coord3d.GlobalCS))\n            {\n                return this.Copy();\n            }\n            else\n            {\n                Vector3d axis = this.ToAxis;\n                double angle = this.ToAngle;\n                axis = axis.ConvertToGlobal();\n                return new Rotation(axis, angle);\n            }\n        }\n\n        /// <summary>\n        /// Convert rotation object to reference coordinate system.\n        /// </summary>\n        public Rotation ConvertTo(Coord3d coord)\n        {\n            if (this._coord == coord)\n            {\n                return this.Copy();\n            } else\n            {\n                Vector3d axis = this.ToAxis;\n                double angle = this.ToAngle;\n                axis = axis.ConvertTo(coord);\n                return new Rotation(axis, angle);\n            }\n        }\n\n\n        /// <summary>\n        /// Determines whether two objects are equal.\n        /// </summary>\n        public override bool Equals(object obj)\n        {\n            if (obj == null || (!object.ReferenceEquals(this.GetType(), obj.GetType())))\n            {\n                return false;\n            }\n            Rotation r = (Rotation)obj;\n            if (GeometRi3D.UseAbsoluteTolerance)\n            {\n                return (this.ToRotationMatrix - r.ConvertTo(this.Coord).ToRotationMatrix).MaxNorm < GeometRi3D.Tolerance;\n            }\n            else\n            {\n                return (this.ToRotationMatrix - r.ConvertTo(this.Coord).ToRotationMatrix).MaxNorm / this.ToRotationMatrix.MaxNorm < GeometRi3D.Tolerance;\n            }\n\n        }\n\n        /// <summary>\n        /// Returns the hashcode for the object.\n        /// </summary>\n        public override int GetHashCode()\n        {\n            return GeometRi3D.HashFunction(_r.Row1.GetHashCode(), \n                                           _r.Row2.GetHashCode(), \n                                           _r.Row3.GetHashCode());\n        }\n\n        /// <summary>\n        /// String representation of an object in global coordinate system.\n        /// </summary>\n        public override string ToString()\n        {\n            return ToString(Coord3d.GlobalCS);\n        }\n\n        /// <summary>\n        /// String representation of an object in reference coordinate system.\n        /// </summary>\n        public string ToString(Coord3d coord)\n        {\n            string nl = System.Environment.NewLine;\n            Rotation r = this.ConvertTo(coord);\n            string str = \"Rotation (reference coord.sys. \" + coord.Name + \"):\" + nl;\n            str += string.Format(\"Row1 -> ({0,10:g5}, {1,10:g5}, {2,10:g5})\", r[0, 0], r[0, 1], r[0, 2]) + nl;\n            str += string.Format(\"Row2 -> ({0,10:g5}, {1,10:g5}, {2,10:g5})\", r[1, 0], r[1, 1], r[1, 2]) + nl;\n            str += string.Format(\"Row3 -> ({0,10:g5}, {1,10:g5}, {2,10:g5})\", r[2, 0], r[2, 1], r[2, 2]);\n            return str;\n        }\n\n        // Operators overloads\n        //-----------------------------------------------------------------\n        public static bool operator ==(Rotation m1, Rotation m2)\n        {\n            if (object.ReferenceEquals(m1, null))\n                return object.ReferenceEquals(m2, null);\n            return m1.Equals(m2);\n        }\n        public static bool operator !=(Rotation m1, Rotation m2)\n        {\n            if (object.ReferenceEquals(m1, null))\n                return !object.ReferenceEquals(m2, null);\n            return !m1.Equals(m2);\n        }\n\n        /// <summary>\n        /// Combine two rotations.\n        /// </summary>\n        public static Rotation operator *(Rotation r1, Rotation r2)\n        {\n            return r1.Mult(r2);\n        }\n\n        /// <summary>\n        /// Multiply rotation matrix by vector.\n        /// <para>The rotation matrix is first transformed into reference coordinate system of vector.</para>\n        /// </summary>\n        public static Vector3d operator *(Rotation r, Vector3d v)\n        {\n            return r.Mult(v);\n        }\n\n        /// <summary>\n        /// Multiply rotation matrix by point.\n        /// <para>The rotation matrix is first transformed into reference coordinate system of point.</para>\n        /// </summary>\n        public static Point3d operator *(Rotation r, Point3d p)\n        {\n            return r.Mult(p);\n        }\n    }\n}\n"
  },
  {
    "path": "GeometRi/Segment3D.cs",
    "content": "﻿using System;\nusing static System.Math;\n\nnamespace GeometRi\n{\n    /// <summary>\n    /// Line segment in 3D space defined by two end points.\n    /// </summary>\n#if NET20_OR_GREATER\n    [Serializable]\n#endif\n    public class Segment3d : LinearFiniteObject, ILinearObject, IFiniteObject\n    {\n        private Point3d _p1;\n        private Point3d _p2;\n\n        private Point3d _center;\n        private double? _length;\n        private Vector3d _dir;\n        private Vector3d _vector;\n        private Line3d _line;\n        private Ray3d _ray;\n\n        private void ClearCache()\n        {\n            _center = null;\n            _length = null;\n            _dir = null;\n            _vector = null;\n            _line = null;\n            _ray = null;\n        }\n\n\n        /// <summary>\n        /// Initializes line segment using two points.\n        /// </summary>\n        public Segment3d(Point3d p1, Point3d p2)\n        {\n            _p1 = p1.Copy();\n            _p2 = p2.ConvertTo(p1.Coord);\n        }\n\n        /// <summary>\n        /// Creates copy of the object\n        /// </summary>\n        public Segment3d Copy()\n        {\n            return new Segment3d(_p1,_p2);\n        }\n\n        public Point3d P1\n        {\n            get { return _p1; }\n            set { _p1 = value.Copy(); ClearCache();}\n        }\n\n        public Point3d P2\n        {\n            get { return _p2; }\n            set { _p2 = value.Copy(); ClearCache(); }\n        }\n\n        public Point3d Center\n        {\n            get\n            {\n                //CheckFields();\n                if (_center == null)\n                {\n                    _center = _p1.Add(_p2, 0.5, 0.5);\n                }\n                return _center;\n            }\n        }\n\n        public double Length\n        {\n            get {\n                //CheckFields();\n                if (_length == null)\n                {\n                    _length = _p1.DistanceTo(_p2);\n                }\n                return _length.Value;\n            }\n        }\n\n        internal override Vector3d Vector\n           {\n               get\n               {\n                   //CheckFields();\n                   if (_vector == null)\n                   {\n                       _vector = new Vector3d(_p1, _p2);\n                   }\n                   return _vector;\n               }\n           }  \n        \n        /// <summary>\n        /// returns a new vector from P1 to P2.\n        /// </summary>\n        public Vector3d ToVector\n        {\n            get { return new Vector3d(_p1, _p2); }\n        }\n\n    \n        internal override Ray3d Ray\n        {\n            get\n            {\n                //CheckFields();\n                if (_ray == null)\n                {\n                    _ray = new Ray3d(_p1, new Vector3d(_p1, _p2));\n                }\n                return _ray;\n            }\n        }\n        /// <summary>\n        /// Returns a new ray starting at P1 and directed towards P2.\n        /// </summary>\n        public Ray3d ToRay\n        {\n            get { return Ray.Copy(); }\n        }\n\n        internal override Line3d Line\n        {\n            get\n            {\n                //CheckFields();\n                if (_line == null)\n                {\n                    _line = new Line3d(_p1, _p2);\n                }\n                return _line;\n            }\n        }\n        /// <summary>\n        /// Returns a new line.\n        /// </summary>\n        public Line3d ToLine\n        {\n            get { return Line.Copy(); }\n        }\n\n        /// <summary>\n        /// Direction vector of the segment\n        /// </summary>\n        /// <returns></returns>\n        public Vector3d Direction\n        {\n            get {\n                //CheckFields();\n                if (_dir == null)\n                {\n                    _dir = Vector.Normalized;\n                }\n                return _dir;\n            }\n        }\n\n        public bool IsOriented\n        {\n            get { return false; }\n        }\n\n        /// <summary>\n        /// Return Axis Aligned Bounding Box (AABB).\n        /// </summary>\n        public AABB AABB()\n        {\n            return new AABB(P1, P2);\n        }\n\n        #region \"ParallelMethods\"\n        /// <summary>\n        /// Check if two objects are parallel\n        /// </summary>\n        public bool IsParallelTo(ILinearObject obj)\n        {\n            return this.Direction.IsParallelTo(obj.Direction);\n        }\n\n        /// <summary>\n        /// Check if two objects are NOT parallel\n        /// </summary>\n        public bool IsNotParallelTo(ILinearObject obj)\n        {\n            return this.Direction.IsNotParallelTo(obj.Direction);\n        }\n\n        /// <summary>\n        /// Check if two objects are orthogonal\n        /// </summary>\n        public bool IsOrthogonalTo(ILinearObject obj)\n        {\n            return this.Direction.IsOrthogonalTo(obj.Direction);\n        }\n\n        /// <summary>\n        /// Check if two objects are parallel\n        /// </summary>\n        public bool IsParallelTo(IPlanarObject obj)\n        {\n            return this.Direction.IsOrthogonalTo(obj.Normal);\n        }\n\n        /// <summary>\n        /// Check if two objects are NOT parallel\n        /// </summary>\n        public bool IsNotParallelTo(IPlanarObject obj)\n        {\n            return !this.Direction.IsOrthogonalTo(obj.Normal);\n        }\n\n        /// <summary>\n        /// Check if two objects are orthogonal\n        /// </summary>\n        public bool IsOrthogonalTo(IPlanarObject obj)\n        {\n            return this.Direction.IsParallelTo(obj.Normal);\n        }\n\n        /// <summary>\n        /// Check if two objects are coplanar\n        /// </summary>\n        public bool IsCoplanarTo(IPlanarObject obj)\n        {\n            return GeometRi3D._coplanar(this, obj);\n        }\n\n        /// <summary>\n        /// Check if two objects are coplanar\n        /// </summary>\n        public bool IsCoplanarTo(ILinearObject obj)\n        {\n            return GeometRi3D._coplanar(this, obj);\n        }\n        #endregion\n\n        #region \"DistanceTo\"\n        /// <summary>\n        /// Returns shortest distance from segment to the point\n        /// </summary>\n        public double DistanceTo(Point3d p)\n        {\n            return p.DistanceTo(this);\n        }\n\n        public double DistanceSquared(Point3d p)\n        {\n            return p.DistanceSquared(this);\n        }\n\n        /// <summary>\n        /// Point on segment closest to target point \"p\".\n        /// </summary>\n        public Point3d ClosestPoint(Point3d p)\n        {\n            Point3d projection_point = p.ProjectionTo(this.Line);\n            if (projection_point.BelongsTo(this))\n            {\n                return projection_point;\n            }\n            else\n            {\n                double dist1 = p.DistanceTo(this.P1);\n                double dist2 = p.DistanceTo(this.P2);\n\n                if (dist1 <= dist2)\n                {\n                    return this.P1;\n                }\n                else\n                {\n                    return this.P2;\n                }\n            }\n        }\n\n        /// <summary>\n        /// Returns shortest distance from segment to the plane\n        /// </summary>\n        public double DistanceTo(Plane3d s)\n        {\n\n            object obj = this.IntersectionWith(s);\n\n            if (obj == null)\n            {\n                return Min(this.P1.DistanceTo(s), this.P2.DistanceTo(s));\n            }\n            else\n            {\n                return 0;\n            }\n        }\n\n        /// <summary>\n        /// Returns shortest distance from segment to the line\n        /// </summary>\n        public double DistanceTo(Line3d l)\n        {\n            Point3d p = l.PerpendicularTo(this.Line);\n            if (p != null && p.BelongsTo(this))\n            {\n                return l.DistanceTo(this.Line);\n            }\n            else\n            {\n                return Min(this.P1.DistanceTo(l), this.P2.DistanceTo(l));\n            }\n        }\n\n        /// <summary>\n        /// Returns shortest distance between two segments\n        /// </summary>\n        public double DistanceTo(Segment3d s)\n        {\n            return _DistanceTo(s, out double sc, out double tc);\n        }\n\n        /// <summary>\n        /// Returns shortest distance between two segments (with closest points)\n        /// </summary>\n        public double DistanceTo(Segment3d s, out Point3d point_on_this_segment, out Point3d point_on_target_segment)\n        {\n            double p1, p2;\n            double dist = _DistanceTo(s, out p1, out p2);\n            //point_on_this_segment = this.P1.Translate(p1 * this.ToVector);\n            //point_on_target_segment = s.P1.Translate(p2 * s.ToVector);\n            point_on_this_segment = this.P1 + p1 * (this.P2 - this.P1);\n            point_on_target_segment = s.P1 + p2 * (s.P2 - s.P1);\n\n            return dist;\n        }\n        internal double _DistanceTo(Segment3d s, out double p1, out double p2)\n        {\n\n            // Algorithm by Dan Sunday\n            // http://geomalgorithms.com/a07-_distance.html\n\n            double small = GeometRi3D.Tolerance;\n\n\n            Vector3d u = this.ToVector;\n            Vector3d v = s.ToVector;\n            Vector3d w = new Vector3d(s.P1, this.P1);\n\n            double a = u * u;\n            double b = u * v;\n            double c = v * v;\n            double d = u * w;\n            double e = v * w;\n\n            //Point3d u = this.P2 - this.P1;\n            //Point3d v = s.P2 - s.P1;\n            //Point3d w = this.P1 - s.P1;\n\n            //double a = u.Dot(u);\n            //double b = u.Dot(v);\n            //double c = v.Dot(v);\n            //double d = u.Dot(w);\n            //double e = v.Dot(w);\n\n            double DD = a * c - b * b;\n            double sc = 0;\n            double sN = 0;\n            double sD = 0;\n            double tc = 0;\n            double tN = 0;\n            double tD = 0;\n            sD = DD;\n            tD = DD;\n\n            if (DD < small)\n            {\n                // the lines are almost parallel, force using point Me.P1 to prevent possible division by 0.0 later\n                sN = 0.0;\n                sD = 1.0;\n                tN = e;\n                tD = c;\n            }\n            else\n            {\n                // get the closest points on the infinite lines\n                sN = (b * e - c * d);\n                tN = (a * e - b * d);\n                if ((sN < 0.0))\n                {\n                    // sc < 0 => the s=0 edge Is visible\n                    sN = 0.0;\n                    tN = e;\n                    tD = c;\n                }\n                else if ((sN > sD))\n                {\n                    // sc > 1  => the s=1 edge Is visible\n                    sN = sD;\n                    tN = e + b;\n                    tD = c;\n                }\n            }\n\n            if ((tN < 0.0))\n            {\n                // tc < 0 => the t=0 edge Is visible\n                tN = 0.0;\n                // recompute sc for this edge\n                if ((-d < 0.0))\n                {\n                    sN = 0.0;\n                }\n                else if ((-d > a))\n                {\n                    sN = sD;\n                }\n                else\n                {\n                    sN = -d;\n                    sD = a;\n                }\n            }\n            else if ((tN > tD))\n            {\n                // tc > 1  => the t=1 edge Is visible\n                tN = tD;\n                // recompute sc for this edge\n                if (((-d + b) < 0.0))\n                {\n                    sN = 0;\n                }\n                else if (((-d + b) > a))\n                {\n                    sN = sD;\n                }\n                else\n                {\n                    sN = (-d + b);\n                    sD = a;\n                }\n            }\n\n            // finally do the division to get sc And tc\n            sc = Abs(sN) < small ? 0.0 : sN / sD;\n            tc = Abs(tN) < small ? 0.0 : tN / tD;\n\n            // get the difference of the two closest points\n            Vector3d dP = w + (sc * u) - (tc * v);\n            //Point3d dP = w + u.Subtract(v, sc, tc);\n            // =  S1(sc) - S2(tc)\n\n            p1 = sc;\n            p2 = tc;\n\n            //return dP.Norm;\n            return Sqrt(dP.X * dP.X + dP.Y * dP.Y + dP.Z * dP.Z);\n\n        }\n\n        /// <summary>\n        /// Returns shortest distance from segment to ray\n        /// </summary>\n        public double DistanceTo(Ray3d r)\n        {\n\n\n            Point3d p1 = this.Line.PerpendicularTo(r.ToLine);\n            Point3d p2 = r.ToLine.PerpendicularTo(this.Line);\n\n            if (p1 != null && p2 != null && p1.BelongsTo(r) && p2.BelongsTo(this))\n            {\n                return this.Line.DistanceTo(r.ToLine);\n            }\n\n            double d1 = double.PositiveInfinity;\n            double d2 = double.PositiveInfinity;\n            double d3 = double.PositiveInfinity;\n            bool flag = false;\n\n            if (r.Point.ProjectionTo(this.Line).BelongsTo(this))\n            {\n                d1 = r.Point.DistanceTo(this.Line);\n                flag = true;\n            }\n            if (this.P1.ProjectionTo(r.ToLine).BelongsTo(r))\n            {\n                d2 = this.P1.DistanceTo(r.ToLine);\n                flag = true;\n            }\n            if (this.P2.ProjectionTo(r.ToLine).BelongsTo(r))\n            {\n                d3 = this.P2.DistanceTo(r.ToLine);\n                flag = true;\n            }\n\n            if (flag)\n                return Min(d1, Min(d2, d3));\n\n            return Min(this.P1.DistanceTo(r.Point), this.P2.DistanceTo(r.Point));\n\n        }\n\n        /// <summary>\n        /// Shortest distance between segment and circle (including interior points)\n        /// </summary>\n        public double DistanceTo(Circle3d c)\n        {\n            return c.DistanceTo(this);\n        }\n\n        /// <summary>\n        /// Shortest distance between segment and sphere\n        /// </summary>\n        public double DistanceTo(Sphere s)\n        {\n            return s.DistanceTo(this);\n        }\n\n        /// <summary>\n        /// Shortest distance between segment and circle (including interior points)\n        /// </summary>\n        /// <param name=\"c\">Target circle</param>\n        /// <param name=\"point_on_segment\">Closest point on segment</param>\n        /// <param name=\"point_on_circle\">Closest point on circle</param>\n        public double DistanceTo(Circle3d c, out Point3d point_on_segment, out Point3d point_on_circle)\n        {\n            return c.DistanceTo(this, out point_on_circle, out point_on_segment);\n        }\n\n        /// <summary>\n        /// Shortest distance between segment and triangle\n        /// </summary>\n        public double DistanceTo(Triangle t)\n        {\n            return t.DistanceTo(this);\n        }\n\n        /// <summary>\n        /// Shortest distance between segment and triangle (with closest points)\n        /// </summary>\n        public double DistanceTo(Triangle t, out Point3d point_on_segment, out Point3d point_on_triangle)\n        {\n            return t.DistanceTo(this, out point_on_triangle, out point_on_segment);\n        }\n\n        /// <summary>\n        /// Shortest distance between segment and convex polyhedron\n        /// </summary>\n        public double DistanceTo(ConvexPolyhedron cp)\n        {\n            return cp.DistanceTo(this);\n        }\n\n        /// <summary>\n        /// Shortest distance between segment and convex polyhedron\n        /// </summary>\n        public double DistanceTo(ConvexPolyhedron cp, out Point3d point_on_segment, out Point3d point_on_polyhedron)\n        {\n            return cp.DistanceTo(this, out point_on_polyhedron, out point_on_segment);\n        }\n        #endregion\n\n        /// <summary>\n        /// <para>Test if segment is located in the epsilon neighborhood of the line.</para>\n        /// <para>Epsilon neighborhood is defined by a GeometRi3D.Tolerance property.</para>\n        /// <para>For relative tolerance tests a fraction of the segment's length is used to define epsilon neighborhood.</para>\n        /// </summary>\n        public bool BelongsTo(Line3d l)\n        {\n            if (GeometRi3D.UseAbsoluteTolerance)\n            {\n                return _p1.BelongsTo(l) && _p2.BelongsTo(l);\n            }\n            else\n            {\n                double tol = GeometRi3D.Tolerance;\n                GeometRi3D.Tolerance = tol * this.Length;\n                GeometRi3D.UseAbsoluteTolerance = true;\n                bool result = this.BelongsTo(l);\n                GeometRi3D.UseAbsoluteTolerance = false;\n                GeometRi3D.Tolerance = tol;\n                return result;\n            }\n        }\n\n        #region \"BoundingBox\"\n        /// <summary>\n        /// Return minimum bounding box.\n        /// </summary>\n        public Box3d MinimumBoundingBox\n        {\n            get\n            {\n                Vector3d v1 = new Vector3d(_p1, _p2).Normalized;\n                Vector3d v2 = v1.OrthogonalVector.Normalized;\n                Vector3d v3 = v1.Cross(v2);\n                Matrix3d m = new Matrix3d(v1, v2, v3);\n                Rotation r = new Rotation(m.Transpose());\n                return new Box3d(0.5 * (_p1 + _p2), Length, 0, 0, r);\n            }\n        }\n\n        /// <summary>\n        /// Return Axis Aligned Bounding Box (AABB) in given coordinate system.\n        /// </summary>\n        public Box3d BoundingBox(Coord3d coord = null)\n        {\n            coord = (coord == null) ? Coord3d.GlobalCS : coord;\n            Line3d l1 = new Line3d(coord.Origin, coord.Xaxis);\n            Line3d l2 = new Line3d(coord.Origin, coord.Yaxis);\n            Line3d l3 = new Line3d(coord.Origin, coord.Zaxis);\n            object s1 = this.ProjectionTo(l1);\n            object s2 = this.ProjectionTo(l2);\n            object s3 = this.ProjectionTo(l3);\n            double lx, ly, lz;\n            if (s1.GetType() == typeof(Segment3d)) { lx = ((Segment3d)s1).Length; } else { lx = 0.0; }\n            if (s2.GetType() == typeof(Segment3d)) { ly = ((Segment3d)s2).Length; } else { ly = 0.0; }\n            if (s3.GetType() == typeof(Segment3d)) { lz = ((Segment3d)s3).Length; } else { lz = 0.0; }\n            return new Box3d(0.5 * (_p1 + _p2), lx, ly, lz, coord);\n        }\n\n        /// <summary>\n        /// Return bounding sphere.\n        /// </summary>\n        public Sphere BoundingSphere\n        {\n            get { return new Sphere(0.5*(_p1+_p2), 0.5*Length); }\n\n        }\n        #endregion\n\n        /// <summary>\n        /// Get intersection of segment with plane.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'.\n        /// </summary>\n        public object IntersectionWith(Plane3d s)\n        {\n\n            object obj = this.Ray.IntersectionWith(s);\n\n            if (obj == null)\n            {\n                return null;\n            }\n            else\n            {\n                if (object.ReferenceEquals(obj.GetType(), typeof(Ray3d)))\n                {\n                    return this;\n                }\n                else\n                {\n                    Ray3d r = new Ray3d(this.P2, new Vector3d(this.P2, this.P1));\n                    object obj2 = r.IntersectionWith(s);\n                    if (obj2 == null)\n                    {\n                        return null;\n                    }\n                    else\n                    {\n                        return (Point3d)obj2;\n                    }\n                }\n            }\n        }\n\n        /// <summary>\n        /// Get intersection of segment with line.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'.\n        /// </summary>\n        public object IntersectionWith(Line3d l)\n        {\n\n            if (this.BelongsTo(l)) { return this.Copy(); }\n\n            Point3d p = l.PerpendicularTo(Line);\n            if (p != null && p.BelongsTo(this) && p.BelongsTo(l))\n            {\n                return p;\n            }\n            else\n            {\n                return null;\n            }\n\n        }\n\n        /// <summary>\n        /// Get intersection of segment with other segment.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'.\n        /// </summary>\n        public object IntersectionWith(Segment3d s)\n        {\n\n            if (this == s) { return this.Copy(); }\n\n            Line3d l1 = this.Line;\n            Line3d l2 = s.Line;\n\n            if (this.BelongsTo(l2) || s.BelongsTo(l1))\n            {\n                // Segments are collinear\n\n                // Relative tolerance check ================================\n                double tol = GeometRi3D.Tolerance;\n                if (!GeometRi3D.UseAbsoluteTolerance)\n                {\n                    tol = GeometRi3D.Tolerance * Max(this.Length, s.Length);\n                }\n                //==========================================================\n\n                // Create local CS with X-axis along segment 's'\n                Vector3d v2 = s.ToVector.OrthogonalVector;\n                Coord3d cs = new Coord3d(s.P1, s.ToVector, v2);\n                double x1 = 0.0;\n                double x2 = s.Length;\n\n                double t3 = this.P1.ConvertTo(cs).X;\n                double t4 = this.P2.ConvertTo(cs).X;\n                double x3 = Min(t3, t4);\n                double x4 = Max(t3, t4);\n\n                // Segments do not overlap\n                if (GeometRi3D.Smaller(x4, x1, tol) || GeometRi3D.Greater(x3, x2, tol)) { return null; }\n\n                // One common point\n                if (GeometRi3D.AlmostEqual(Max(x3, x4), x1, tol)) { return new Point3d(x1, 0, 0, cs); }\n                if (GeometRi3D.AlmostEqual(Min(x3, x4), x2, tol)) { return new Point3d(x2, 0, 0, cs); }\n\n                // Overlaping segments\n                x1 = Max(x1, x3);\n                x2 = Min(x2, x4);\n                return new Segment3d(new Point3d(x1, 0, 0, cs), new Point3d(x2, 0, 0, cs));\n            }\n            else\n            {\n                Point3d p = l1.PerpendicularTo(l2);\n                if (p != null && p.BelongsTo(this) && p.BelongsTo(s))\n                {\n                    return p;\n                }\n                else\n                {\n                    return null;\n                }\n            }\n        }\n\n        /// <summary>\n        /// Get intersection of segment with sphere.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'.\n        /// </summary>\n        public object IntersectionWith(Sphere s)\n        {\n            return s.IntersectionWith(this);\n        }\n\n        /// <summary>\n        /// Get intersection of segment with ellipsoid.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'.\n        /// </summary>\n        public object IntersectionWith(Ellipsoid e)\n        {\n            return e.IntersectionWith(this);\n        }\n\n        /// <summary>\n        /// Get intersection of segment with ellipse.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'.\n        /// </summary>\n        public object IntersectionWith(Ellipse e)\n        {\n            return e.IntersectionWith(this);\n        }\n\n        /// <summary>\n        /// Get intersection of segment with circle.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'.\n        /// </summary>\n        public object IntersectionWith(Circle3d c)\n        {\n            return c.IntersectionWith(this);\n        }\n\n        /// <summary>\n        /// Get intersection of segment with ray.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'.\n        /// </summary>\n        public object IntersectionWith(Ray3d r)\n        {\n            return r.IntersectionWith(this);\n        }\n\n        /// <summary>\n        /// Get intersection of segment with triangle.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'.\n        /// </summary>\n        public object IntersectionWith(Triangle t)\n        {\n            return t.IntersectionWith(this);\n        }\n\n        /// <summary>\n        /// Get intersection of segment with box.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'.\n        /// </summary>\n        public object IntersectionWith(Box3d b)\n        {\n            return b.IntersectionWith(this);\n        }\n\n        /// <summary>\n        /// Intersection check between segment and circle\n        /// </summary>\n        public bool Intersects(Circle3d c)\n        {\n            return this.IntersectionWith(c) != null;\n        }\n\n        /// <summary>\n        /// Intersection check between segment and polyhedron\n        /// Behaviour for touching objects is undefined.\n        /// </summary>\n        public bool Intersects(ConvexPolyhedron c)\n        {\n            return this.Intersects(c);\n        }\n\n        /// <summary>\n        /// Get the orthogonal projection of a segment to the line.\n        /// Return object of type 'Segment3d' or 'Point3d'\n        /// </summary>\n        public object ProjectionTo(Line3d l)\n        {\n            if (this.ToVector.IsOrthogonalTo(l.Direction))\n            {\n                // Segment is perpendicular to the line\n                return this.P1.ProjectionTo(l);\n            }\n            else\n            {\n                return new Segment3d(this.P1.ProjectionTo(l), this.P2.ProjectionTo(l));\n            }\n        }\n\n        /// <summary>\n        /// Get the orthogonal projection of a segment to the plane.\n        /// Return object of type 'Segment3d' or 'Point3d'\n        /// </summary>\n        public object ProjectionTo(Plane3d s)\n        {\n            if (this.ToVector.IsParallelTo(s.Normal))\n            {\n                // Segment is perpendicular to the plane\n                return this.P1.ProjectionTo(s);\n            }\n            else\n            {\n                return new Segment3d(this.P1.ProjectionTo(s), this.P2.ProjectionTo(s));\n            }\n        }\n\n        internal override int _PointLocation(Point3d p)\n        {\n            if (GeometRi3D.UseAbsoluteTolerance)\n            {\n                Point3d proj = p.ProjectionTo(this.Line);\n                if (GeometRi3D.AlmostEqual(p.DistanceTo(proj),0))\n                {\n                    return _AxialPointLocation(p);\n                }\n                else\n                {\n                    return -1; // Point is outside\n                }\n            }\n            else\n            {\n                double tol = GeometRi3D.Tolerance;\n                GeometRi3D.Tolerance = tol * this.Length;\n                GeometRi3D.UseAbsoluteTolerance = true;\n                int result = this._PointLocation(p);\n                GeometRi3D.UseAbsoluteTolerance = false;\n                GeometRi3D.Tolerance = tol;\n                return result;\n            }\n        }\n\n        internal int _AxialPointLocation(Point3d p)\n        {\n            if (GeometRi3D.UseAbsoluteTolerance)\n            {\n                double dist1 = p.DistanceTo(this._p1);\n                if (GeometRi3D.AlmostEqual(dist1, 0))\n                {\n                    return 0; // Point is on boundary\n                }\n                double dist2 = p.DistanceTo(this._p2);\n                if (GeometRi3D.AlmostEqual(dist2, 0))\n                {\n                    return 0; // Point is on boundary\n                }\n                \n                double s_len = this.Length;\n                if (dist1 <= s_len && dist2 <= s_len)\n                {\n                    return 1; // // Point is strictly inside\n                }\n\n                if (dist1 < dist2)\n                {\n                    return -1; // Point is outside of the P1\n                }\n                else\n                {\n                    return -2; // Point is outside of the P2\n                }\n            }\n            else\n            {\n                double tol = GeometRi3D.Tolerance;\n                GeometRi3D.Tolerance = tol * this.Length;\n                GeometRi3D.UseAbsoluteTolerance = true;\n                int result = this._AxialPointLocation(p);\n                GeometRi3D.UseAbsoluteTolerance = false;\n                GeometRi3D.Tolerance = tol;\n                return result;\n            }\n        }\n\n        #region \"AngleTo\"\n        /// <summary>\n        /// Angle between two objects in radians (0 &lt; angle &lt; Pi)\n        /// </summary>\n        public double AngleTo(ILinearObject obj)\n        {\n            return GeometRi3D.GetAngle(this, obj);\n        }\n        /// <summary>\n        /// Angle between two objects in degrees (0 &lt; angle &lt; 180)\n        /// </summary>\n        public double AngleToDeg(ILinearObject obj)\n        {\n            return AngleTo(obj) * 180 / PI;\n        }\n\n        /// <summary>\n        /// Angle between two objects in radians (0 &lt; angle &lt; Pi)\n        /// </summary>\n        public double AngleTo(IPlanarObject obj)\n        {\n            return GeometRi3D.GetAngle(this, obj);\n        }\n        /// <summary>\n        /// Angle between two objects in degrees (0 &lt; angle &lt; 180)\n        /// </summary>\n        public double AngleToDeg(IPlanarObject obj)\n        {\n            return AngleTo(obj) * 180 / PI;\n        }\n        #endregion\n\n        #region \"TranslateRotateReflect\"\n        /// <summary>\n        /// Translate segment by a vector\n        /// </summary>\n        public Segment3d Translate(Vector3d v)\n        {\n            return new Segment3d(P1.Translate(v), P2.Translate(v));\n        }\n\n        /// <summary>\n        /// Rotate segment by a given rotation matrix\n        /// </summary>\n        [System.Obsolete(\"use Rotation object and specify rotation center: this.Rotate(Rotation r, Point3d p)\")]\n        public virtual Segment3d Rotate(Matrix3d m)\n        {\n            return new Segment3d(P1.Rotate(m), P2.Rotate(m));\n        }\n\n        /// <summary>\n        /// Rotate segment by a given rotation matrix around point 'p' as a rotation center\n        /// </summary>\n        [System.Obsolete(\"use Rotation object: this.Rotate(Rotation r, Point3d p)\")]\n        public virtual Segment3d Rotate(Matrix3d m, Point3d p)\n        {\n            return new Segment3d(P1.Rotate(m, p), P2.Rotate(m, p));\n        }\n\n        /// <summary>\n        /// Rotate segment around point 'p' as a rotation center\n        /// </summary>\n        public virtual Segment3d Rotate(Rotation r, Point3d p)\n        {\n            return new Segment3d(P1.Rotate(r, p), P2.Rotate(r, p));\n        }\n\n        /// <summary>\n        /// Reflect segment in given point\n        /// </summary>\n        public virtual Segment3d ReflectIn(Point3d p)\n        {\n            return new Segment3d(P1.ReflectIn(p), P2.ReflectIn(p));\n        }\n\n        /// <summary>\n        /// Reflect segment in given line\n        /// </summary>\n        public virtual Segment3d ReflectIn(Line3d l)\n        {\n            return new Segment3d(P1.ReflectIn(l), P2.ReflectIn(l));\n        }\n\n        /// <summary>\n        /// Reflect segment in given plane\n        /// </summary>\n        public virtual Segment3d ReflectIn(Plane3d s)\n        {\n            return new Segment3d(P1.ReflectIn(s), P2.ReflectIn(s));\n        }\n\n        /// <summary>\n        /// Scale segment relative to given point\n        /// </summary>\n        public virtual Segment3d Scale(double scale, Point3d scaling_center)\n        {\n            Point3d new_p1 = scaling_center + scale * (this._p1 - scaling_center);\n            Point3d new_p2 = scaling_center + scale * (this._p2 - scaling_center);\n            return new Segment3d(new_p1, new_p2);\n        }\n\n        /// <summary>\n        /// Scale segment relative to its center\n        /// </summary>\n        public virtual Segment3d Scale(double scale)\n        {\n            Point3d scaling_center = this.Center;\n            Point3d new_p1 = scaling_center + scale * (this._p1 - scaling_center);\n            Point3d new_p2 = scaling_center + scale * (this._p2 - scaling_center);\n            return new Segment3d(new_p1, new_p2);\n        }\n        #endregion\n\n        /// <summary>\n        /// Determines whether two objects are equal.\n        /// </summary>\n        public override bool Equals(object obj)\n        {\n            if (obj == null || (!object.ReferenceEquals(this.GetType(), obj.GetType())))\n            {\n                return false;\n            }\n            Segment3d s = (Segment3d)obj;\n            if (GeometRi3D.UseAbsoluteTolerance)\n            {\n                return (this.P1 == s.P1 && this.P2 == s.P2) | (this.P1 == s.P2 && this.P2 == s.P1);\n            }\n            else\n            {\n                double tol = GeometRi3D.Tolerance;\n                GeometRi3D.Tolerance = tol * this.Length;\n                GeometRi3D.UseAbsoluteTolerance = true;\n                bool result = (this.P1 == s.P1 && this.P2 == s.P2) | (this.P1 == s.P2 && this.P2 == s.P1);\n                GeometRi3D.UseAbsoluteTolerance = false;\n                GeometRi3D.Tolerance = tol;\n                return result;\n            }\n        }\n\n        /// <summary>\n        /// Returns the hashcode for the object.\n        /// </summary>\n        public override int GetHashCode()\n        {\n            return GeometRi3D.HashFunction(_p1.GetHashCode(), _p2.GetHashCode());\n        }\n\n        /// <summary>\n        /// String representation of an object in global coordinate system.\n        /// </summary>\n        public override String ToString()\n        {\n            return ToString(Coord3d.GlobalCS);\n        }\n\n        /// <summary>\n        /// String representation of an object in reference coordinate system.\n        /// </summary>\n        public String ToString(Coord3d coord)\n        {\n            System.Text.StringBuilder str = new System.Text.StringBuilder();\n            string nl = System.Environment.NewLine;\n\n            if (coord == null) { coord = Coord3d.GlobalCS; }\n            Point3d p1 = _p1.ConvertTo(coord);\n            Point3d p2 = _p2.ConvertTo(coord);\n\n            str.Append(\"Segment:\" + nl);\n            str.Append(string.Format(\"Point 1  -> ({0,10:g5}, {1,10:g5}, {2,10:g5})\", p1.X, p1.Y, p1.Z) + nl);\n            str.Append(string.Format(\"Point 2 -> ({0,10:g5}, {1,10:g5}, {2,10:g5})\", p2.X, p2.Y, p2.Z));\n            return str.ToString();\n        }\n\n        // Operators overloads\n        //-----------------------------------------------------------------\n        public static bool operator ==(Segment3d l1, Segment3d l2)\n        {\n            if (object.ReferenceEquals(l1, null))\n                return object.ReferenceEquals(l2, null);\n            return l1.Equals(l2);\n        }\n        public static bool operator !=(Segment3d l1, Segment3d l2)\n        {\n            if (object.ReferenceEquals(l1, null))\n                return !object.ReferenceEquals(l2, null);\n            return !l1.Equals(l2);\n        }\n\n    }\n}\n\n\n"
  },
  {
    "path": "GeometRi/Sphere.cs",
    "content": "﻿using System;\nusing static System.Math;\n\nnamespace GeometRi\n{\n    /// <summary>\n    /// Sphere object defined by center point and radius.\n    /// </summary>\n#if NET20_OR_GREATER\n    [Serializable]\n#endif\n    public class Sphere : FiniteObject, IFiniteObject\n    {\n\n        internal Point3d _point;\n        private double _r;\n\n        /// <summary>\n        /// Initializes sphere using center point and radius.\n        /// </summary>\n        public Sphere(Point3d P, double R)\n        {\n            _point = P.Copy();\n            _r = R;\n        }\n\n        /// <summary>\n        /// Creates copy of the object\n        /// </summary>\n        public Sphere Copy()\n        {\n            return new Sphere(_point,_r);\n        }\n\n#region \"Properties\"\n        /// <summary>\n        /// Center of the sphere\n        /// </summary>\n        public Point3d Center\n        {\n            get { return _point; }\n            set { _point = value.Copy(); }\n        }\n\n        /// <summary>\n        /// X component of the spheres' center\n        /// </summary>\n        public double X\n        {\n            get { return _point.X; }\n            //set { _point.X = value; }\n        }\n\n        /// <summary>\n        /// Y component of the spheres' center\n        /// </summary>\n        public double Y\n        {\n            get { return _point.Y; }\n            //set { _point.Y = value; }\n        }\n\n        /// <summary>\n        /// Z component of the spheres' center\n        /// </summary>\n        public double Z\n        {\n            get { return _point.Z; }\n            //set { _point.Z = value; }\n        }\n\n        /// <summary>\n        /// Radius of the sphere\n        /// </summary>\n        public double R\n        {\n            get { return _r; }\n            set { _r = value; }\n        }\n\n        public double Area\n        {\n            get { return 4.0 * PI * Math.Pow(_r, 2); }\n        }\n\n        public double Volume\n        {\n            get { return 4.0 / 3.0 * PI * Math.Pow(_r, 3); }\n        }\n#endregion\n\n#region \"DistanceTo\"\n        /// <summary>\n        /// Shortest distance between point and sphere (including interior points).\n        /// </summary>\n        public double DistanceTo(Point3d p)\n        {\n            double d = p.DistanceTo(this._point);\n            if (d > this.R)\n            {\n                return d - this.R;\n            }\n            else\n            {\n                return 0;\n            }\n        }\n\n        /// <summary>\n        /// Shortest distance between sphere and line\n        /// </summary>\n        public double DistanceTo(Line3d l)\n        {\n            double d = l.DistanceTo(this._point);\n            if (d > this.R)\n            {\n                return d - this.R;\n            }\n            else\n            {\n                return 0;\n            }\n        }\n\n        /// <summary>\n        /// Shortest distance between sphere and ray\n        /// </summary>\n        public double DistanceTo(Ray3d r)\n        {\n            double dist = _point.DistanceTo(r) - _r;\n            return dist < 0 ? 0 : dist;\n        }\n\n        /// <summary>\n        /// Shortest distance between sphere and segment\n        /// </summary>\n        public double DistanceTo(Segment3d s)\n        {\n            double dist = _point.DistanceTo(s) - _r;\n            return dist < 0 ? 0 : dist;\n        }\n\n        /// <summary>\n        /// Shortest distance between sphere and plane\n        /// </summary>\n        public double DistanceTo(Plane3d s)\n        {\n            double d = this._point.DistanceTo(s);\n            if (d > this.R)\n            {\n                return d - this.R;\n            }\n            else\n            {\n                return 0;\n            }\n        }\n\n        /// <summary>\n        /// Shortest distance between sphere and circle (including interior points) (approximate solution)\n        /// </summary>\n        public double DistanceTo(Circle3d c)\n        {\n            return c.DistanceTo(this);\n        }\n\n        /// <summary>\n        /// Shortest distance between sphere and circle (including interior points) (approximate solution).\n        /// <para> The output points may be not unique in case of intersecting objects.</para>\n        /// </summary>\n        /// <param name=\"c\">Target circle</param>\n        /// <param name=\"p1\">Closest point on sphere</param>\n        /// <param name=\"p2\">Closest point on circle</param>\n        public double DistanceTo(Circle3d c, out Point3d p1, out Point3d p2)\n        {\n            return c.DistanceTo(this, out p2, out p1);\n        }\n\n        /// <summary>\n        /// Shortest distance between two spheres.\n        /// <para> Zero distance is returned if one sphere located inside other.</para>\n        /// </summary>\n        public double DistanceTo(Sphere s)\n        {\n            double dist = this._point.DistanceTo(s._point);\n            if (dist <= this.R + s.R)\n            {\n                return 0;\n            }\n            else\n            {\n                return dist - this.R - s.R;\n            }\n        }\n\n        /// <summary>\n        /// Shortest distance between two spheres.\n        /// <para> Zero distance is returned if one sphere is located inside the other.</para>\n        /// <para> The output points may be not unique in case of touching objects.</para>\n        /// </summary>\n        /// <param name=\"s\">Target sphere</param>\n        /// <param name=\"p1\">Closest point on source sphere</param>\n        /// <param name=\"p2\">Closest point on target sphere</param>\n        public double DistanceTo(Sphere s, out Point3d p1, out Point3d p2)\n        {\n            double dist = this._point.DistanceTo(s._point);\n            if (dist <= this.R + s.R)\n            {\n                if (this._point == s._point)\n                {\n                    p1 = this._point.Translate(this.R * new Vector3d(1, 0, 0));\n                    p2 = s._point.Translate(s.R * new Vector3d(1, 0, 0));\n                }\n                else\n                {\n                    p1 = this._point.Translate(this.R * new Vector3d(this._point, s._point).Normalized);\n                    p2 = s._point.Translate(s.R * new Vector3d(s._point, this._point).Normalized);\n                }\n                return 0;\n            }\n            else\n            {\n                p1 = this._point.Translate(this.R * new Vector3d(this._point, s._point).Normalized);\n                p2 = s._point.Translate(s.R * new Vector3d(s._point, this._point).Normalized);\n                return dist - this.R - s.R;\n            }\n        }\n\n        /// <summary>\n        /// Shortest distance from box to sphere\n        /// </summary>\n        public double DistanceTo(Box3d box)\n        {\n            return box.DistanceTo(this);\n        }\n\n        /// <summary>\n        /// Distance from polyhedron to sphere\n        /// </summary>\n        public double DistanceTo(ConvexPolyhedron cp)\n        {\n            return cp.DistanceTo(this);\n        }\n\n        #endregion\n\n        #region \"BoundingBox\"\n        /// <summary>\n        /// Return minimum bounding box.\n        /// </summary>\n        public Box3d MinimumBoundingBox\n        {\n            get { return new Box3d(_point, 2.0 * _r, 2.0 * _r, 2.0 * _r); }\n        }\n\n        /// <summary>\n        /// Return Bounding Box in given coordinate system.\n        /// </summary>\n        public Box3d BoundingBox(Coord3d coord = null)\n        {\n            coord = (coord == null) ? Coord3d.GlobalCS : coord;\n            return new Box3d(_point, 2.0 * _r, 2.0 * _r, 2.0 * _r, new Rotation(coord));\n        }\n\n        /// <summary>\n        /// Return Axis Aligned Bounding Box (AABB).\n        /// </summary>\n        public AABB AABB()\n        {\n            return new AABB(_point, 2.0 * _r, 2.0 * _r, 2.0 * _r);\n        }\n\n        /// <summary>\n        /// Return bounding sphere.\n        /// </summary>\n        public Sphere BoundingSphere\n        {\n            get { return this; }\n\n        }\n\n        /// <summary>\n        /// Check if sphere is located inside box with tolerance defined by global tolerance property (GeometRi3D.Tolerance).\n        /// </summary>\n        public bool IsInside(Box3d box)\n        {\n            // Relative tolerance ================================\n            if (!GeometRi3D.UseAbsoluteTolerance)\n            {\n                double tol = GeometRi3D.Tolerance;\n                GeometRi3D.Tolerance = tol * this.R;\n                GeometRi3D.UseAbsoluteTolerance = true;\n                bool result = this.IsInside(box);\n                GeometRi3D.UseAbsoluteTolerance = false;\n                GeometRi3D.Tolerance = tol;\n                return result;\n            }\n            //====================================================\n\n            if (!this._point.IsInside(box)) return false;\n\n            Coord3d local_coord = box.LocalCoord();\n            Point3d p = _point.ConvertTo(local_coord);\n\n            if (box.L1 / 2 - (Abs(p.X) + this._r) < GeometRi3D.Tolerance) return false;\n            if (box.L2 / 2 - (Abs(p.Y) + this._r) < GeometRi3D.Tolerance) return false;\n            if (box.L3 / 2 - (Abs(p.Z) + this._r) < GeometRi3D.Tolerance) return false;\n\n            return true;\n        }\n\n        #endregion\n\n        /// <summary>\n        /// Point on sphere's surface closest to target point \"p\".\n        /// </summary>\n        public Point3d ClosestPoint(Point3d p)\n        {\n            if (p == this.Center)\n            {\n                // return any point on surface\n                return this.Center.Translate(this.R * new Vector3d(1, 0, 0));\n            }\n            else\n            {\n                return this.Center.Translate(this.R * new Vector3d(this.Center, p).Normalized);\n            }\n        }\n\n        #region \"Intersections\"\n        /// <summary>\n        /// Get intersection of line with sphere.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'.\n        /// </summary>\n        public object IntersectionWith(Line3d l)\n        {\n\n            // Relative tolerance ================================\n            if (!GeometRi3D.UseAbsoluteTolerance)\n            {\n                double tol = GeometRi3D.Tolerance;\n                GeometRi3D.Tolerance = tol * this.R;\n                GeometRi3D.UseAbsoluteTolerance = true;\n                object result = this.IntersectionWith(l);\n                GeometRi3D.UseAbsoluteTolerance = false;\n                GeometRi3D.Tolerance = tol;\n                return result;\n            }\n            //====================================================\n\n            double d = l.Direction.Normalized * (l.Point.ToVector - this.Center.ToVector);\n            double det = Math.Pow(d, 2) - Math.Pow(((l.Point.ToVector - this.Center.ToVector).Norm), 2) + Math.Pow(_r, 2);\n\n            if (det < -GeometRi3D.Tolerance)\n            {\n                return null;\n            }\n            else if (det < GeometRi3D.Tolerance)\n            {\n                return l.Point - d * l.Direction.Normalized.ToPoint;\n            }\n            else\n            {\n                Point3d p1 = l.Point + (-d + Sqrt(det)) * l.Direction.Normalized.ToPoint;\n                Point3d p2 = l.Point + (-d - Sqrt(det)) * l.Direction.Normalized.ToPoint;\n                return new Segment3d(p1, p2);\n            }\n\n        }\n\n        /// <summary>\n        /// Get intersection of segment with sphere.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'.\n        /// </summary>\n        public object IntersectionWith(Segment3d s)\n        {\n\n            // Relative tolerance ================================\n            if (!GeometRi3D.UseAbsoluteTolerance)\n            {\n                double tol = GeometRi3D.Tolerance;\n                GeometRi3D.Tolerance = tol * this.R;\n                GeometRi3D.UseAbsoluteTolerance = true;\n                object result = this.IntersectionWith(s);\n                GeometRi3D.UseAbsoluteTolerance = false;\n                GeometRi3D.Tolerance = tol;\n                return result;\n            }\n            //====================================================\n\n            object obj = this.IntersectionWith(s.Line);\n\n            if (obj == null)\n            {\n                return null;\n            }\n            else if (obj.GetType() == typeof(Point3d))\n            {\n                Point3d p = (Point3d)obj;\n                if (p.BelongsTo(s))\n                {\n                    return p;\n                }\n                else\n                {\n                    return null;\n                }\n            }\n            else\n            {\n                return s.IntersectionWith((Segment3d)obj);\n            }\n\n        }\n\n        /// <summary>\n        /// Get intersection of ray with sphere.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'.\n        /// </summary>\n        public object IntersectionWith(Ray3d r)\n        {\n\n            // Relative tolerance ================================\n            if (!GeometRi3D.UseAbsoluteTolerance)\n            {\n                double tol = GeometRi3D.Tolerance;\n                GeometRi3D.Tolerance = tol * this.R;\n                GeometRi3D.UseAbsoluteTolerance = true;\n                object result = this.IntersectionWith(r);\n                GeometRi3D.UseAbsoluteTolerance = false;\n                GeometRi3D.Tolerance = tol;\n                return result;\n            }\n            //====================================================\n\n            object obj = this.IntersectionWith(r.ToLine);\n\n            if (obj == null)\n            {\n                return null;\n            }\n            else if (obj.GetType() == typeof(Point3d))\n            {\n                Point3d p = (Point3d)obj;\n                if (p.BelongsTo(r))\n                {\n                    return p;\n                }\n                else\n                {\n                    return null;\n                }\n            }\n            else\n            {\n                return r.IntersectionWith((Segment3d)obj);\n            }\n\n        }\n\n        /// <summary>\n        /// Get intersection of plane with sphere.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Circle3d'.\n        /// </summary>\n        public object IntersectionWith(Plane3d s)\n        {\n\n            // Relative tolerance ================================\n            if (!GeometRi3D.UseAbsoluteTolerance)\n            {\n                double tol = GeometRi3D.Tolerance;\n                GeometRi3D.Tolerance = tol * this.R;\n                GeometRi3D.UseAbsoluteTolerance = true;\n                object result = this.IntersectionWith(s);\n                GeometRi3D.UseAbsoluteTolerance = false;\n                GeometRi3D.Tolerance = tol;\n                return result;\n            }\n            //====================================================\n\n            s.SetCoord(this.Center.Coord);\n            double d1 = s.A * this.X + s.B * this.Y + s.C * this.Z + s.D;\n            double d2 = Math.Pow(s.A, 2) + Math.Pow(s.B, 2) + Math.Pow(s.C, 2);\n            double d = Abs(d1) / Sqrt(d2);\n\n            if (d > this.R + GeometRi3D.Tolerance)\n            {\n                return null;\n            }\n            else\n            {\n                double Xc = this.X - s.A * d1 / d2;\n                double Yc = this.Y - s.B * d1 / d2;\n                double Zc = this.Z - s.C * d1 / d2;\n\n                if (Abs(d - this.R) < GeometRi3D.Tolerance)\n                {\n                    return new Point3d(Xc, Yc, Zc, this.Center.Coord);\n                }\n                else\n                {\n                    double R = Sqrt(Math.Pow(this.R, 2) - Math.Pow(d, 2));\n                    return new Circle3d(new Point3d(Xc, Yc, Zc, this.Center.Coord), R, s.Normal);\n                }\n            }\n        }\n\n        /// <summary>\n        /// Get intersection of two spheres.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Circle3d'.\n        /// </summary>\n        public object IntersectionWith(Sphere s)\n        {\n            \n            // Relative tolerance ================================\n            if (!GeometRi3D.UseAbsoluteTolerance)\n            {\n                double tol = GeometRi3D.Tolerance;\n                GeometRi3D.Tolerance = tol * Max(this.R, s.R);\n                GeometRi3D.UseAbsoluteTolerance = true;\n                object result = this.IntersectionWith(s);\n                GeometRi3D.UseAbsoluteTolerance = false;\n                GeometRi3D.Tolerance = tol;\n                return result;\n            }\n            //====================================================\n\n            Point3d p = s.Center.ConvertTo(this.Center.Coord);\n            double Dist = Sqrt(Math.Pow((this.X - p.X), 2) + Math.Pow((this.Y - p.Y), 2) + Math.Pow((this.Z - p.Z), 2));\n\n            // Separated spheres\n            if (Dist > this.R + s.R + GeometRi3D.Tolerance)\n                return null;\n\n            // One sphere inside the other\n            if (Dist < Abs(this.R - s.R) - GeometRi3D.Tolerance)\n                return null;\n\n            // Intersection plane\n            double A = 2 * (p.X - this.X);\n            double B = 2 * (p.Y - this.Y);\n            double C = 2 * (p.Z - this.Z);\n            double D = Math.Pow(this.X, 2) - Math.Pow(p.X, 2) + Math.Pow(this.Y, 2) - Math.Pow(p.Y, 2) + Math.Pow(this.Z, 2) - Math.Pow(p.Z, 2) - Math.Pow(this.R, 2) + Math.Pow(s.R, 2);\n\n            // Intersection center\n            double t = (this.X * A + this.Y * B + this.Z * C + D) / (A * (this.X - p.X) + B * (this.Y - p.Y) + C * (this.Z - p.Z));\n            double x = this.X + t * (p.X - this.X);\n            double y = this.Y + t * (p.Y - this.Y);\n            double z = this.Z + t * (p.Z - this.Z);\n\n            // Outer tangency\n            if (Abs(this.R + s.R - D) < GeometRi3D.Tolerance)\n                return new Point3d(x, y, z, this.Center.Coord);\n\n            // Inner tangency\n            if (Abs(Abs(this.R - s.R) - D) < GeometRi3D.Tolerance)\n                return new Point3d(x, y, z, this.Center.Coord);\n\n            // Intersection\n            double alpha = Acos((Math.Pow(this.R, 2) + Math.Pow(Dist, 2) - Math.Pow(s.R, 2)) / (2 * this.R * Dist));\n            double R = this.R * Sin(alpha);\n            Vector3d v = new Vector3d(this.Center, s.Center);\n\n            return new Circle3d(new Point3d(x, y, z, this.Center.Coord), R, v);\n\n        }\n        #endregion\n\n        /// <summary>\n        /// Intersection check between circle and sphere\n        /// </summary>\n        public bool Intersects(Circle3d c)\n        {\n            return c.Intersects(this);\n        }\n\n        /// <summary>\n        /// Intersection check between sphere and triangle\n        /// </summary>\n        public bool Intersects(Triangle t)\n        {\n            return t.Intersects(this);\n        }\n\n        /// <summary>\n        /// Orthogonal projection of the sphere to the plane\n        /// </summary>\n        public Circle3d ProjectionTo(Plane3d s)\n        {\n            Point3d p = this.Center.ProjectionTo(s);\n            return new Circle3d(p, this.R, s.Normal);\n        }\n\n        /// <summary>\n        /// Orthogonal projection of the sphere to the line\n        /// </summary>\n        public Segment3d ProjectionTo(Line3d l)\n        {\n            Point3d p = this.Center.ProjectionTo(l);\n            return new Segment3d(p.Translate(this.R * l.Direction.Normalized), p.Translate(-this.R * l.Direction.Normalized));\n        }\n\n        internal override int _PointLocation(Point3d p)\n        {\n\n            if (GeometRi3D.UseAbsoluteTolerance)\n            {\n                if (p.DistanceTo(this.Center) - this.R <= GeometRi3D.Tolerance )\n                {\n                    if (p.DistanceTo(this.Center) - this.R < -GeometRi3D.Tolerance )\n                    {\n                        return 1; // Point is strictly inside box\n                    }\n                    else\n                    {\n                        return 0; // Point is on boundary\n                    }\n                }\n                else\n                {\n                    return -1; // Point is outside\n                }\n            }\n            else\n            {\n                double tol = GeometRi3D.Tolerance;\n                GeometRi3D.Tolerance = tol * this.R;\n                GeometRi3D.UseAbsoluteTolerance = true;\n                int result = this._PointLocation(p);\n                GeometRi3D.UseAbsoluteTolerance = false;\n                GeometRi3D.Tolerance = tol;\n                return result;\n            }\n        }\n\n        #region \"TranslateRotateReflect\"\n        /// <summary>\n        /// Translate sphere by a vector\n        /// </summary>\n        public Sphere Translate(Vector3d v)\n        {\n            return new Sphere(this.Center.Translate(v), this.R);\n        }\n\n        /// <summary>\n        /// Rotate sphere by a given rotation matrix\n        /// </summary>\n        [System.Obsolete(\"use Rotation object and specify rotation center: this.Rotate(Rotation r, Point3d p)\")]\n        public Sphere Rotate(Matrix3d m)\n        {\n            return new Sphere(this.Center.Rotate(m), this.R);\n        }\n\n        /// <summary>\n        /// Rotate sphere by a given rotation matrix around point 'p' as a rotation center\n        /// </summary>\n        [System.Obsolete(\"use Rotation object: this.Rotate(Rotation r, Point3d p)\")]\n        public Sphere Rotate(Matrix3d m, Point3d p)\n        {\n            return new Sphere(this.Center.Rotate(m, p), this.R);\n        }\n\n        /// <summary>\n        /// Rotate sphere around point 'p' as a rotation center\n        /// </summary>\n        public Sphere Rotate(Rotation r, Point3d p)\n        {\n            return new Sphere(this.Center.Rotate(r, p), this.R);\n        }\n\n        /// <summary>\n        /// Reflect sphere in given point\n        /// </summary>\n        public Sphere ReflectIn(Point3d p)\n        {\n            return new Sphere(this.Center.ReflectIn(p), this.R);\n        }\n\n        /// <summary>\n        /// Reflect sphere in given line\n        /// </summary>\n        public Sphere ReflectIn(Line3d l)\n        {\n            return new Sphere(this.Center.ReflectIn(l), this.R);\n        }\n\n        /// <summary>\n        /// Reflect sphere in given plane\n        /// </summary>\n        public Sphere ReflectIn(Plane3d s)\n        {\n            return new Sphere(this.Center.ReflectIn(s), this.R);\n        }\n\n        /// <summary>\n        /// Scale sphere relative to given point\n        /// </summary>\n        public virtual Sphere Scale(double scale, Point3d scaling_center)\n        {\n            Point3d new_center = scaling_center + scale * (this.Center - scaling_center);\n            return new Sphere(new_center, _r * scale);\n        }\n        #endregion\n\n        /// <summary>\n        /// Determines whether two objects are equal.\n        /// </summary>\n        public override bool Equals(object obj)\n        {\n            if (obj == null || (!object.ReferenceEquals(this.GetType(), obj.GetType())))\n            {\n                return false;\n            }\n            Sphere s = (Sphere)obj;\n            if (GeometRi3D.UseAbsoluteTolerance)\n            {\n                return s.Center == this.Center && Abs(s.R - this.R) <= GeometRi3D.Tolerance;\n            }\n            else\n            {\n                return this.Center.DistanceTo(s.Center) <= GeometRi3D.Tolerance * this.R && \n                       Abs(s.R - this.R) <= GeometRi3D.Tolerance * this.R;\n            }\n\n        }\n\n        /// <summary>\n        /// Returns the hashcode for the object.\n        /// </summary>\n        public override int GetHashCode()\n        {\n            return GeometRi3D.HashFunction(_point.GetHashCode(), _r.GetHashCode());\n        }\n\n        /// <summary>\n        /// String representation of an object in global coordinate system.\n        /// </summary>\n        public override String ToString()\n        {\n            return ToString(Coord3d.GlobalCS);\n        }\n\n        /// <summary>\n        /// String representation of an object in reference coordinate system.\n        /// </summary>\n        public String ToString(Coord3d coord)\n        {\n            string nl = System.Environment.NewLine;\n\n            if (coord == null) { coord = Coord3d.GlobalCS; }\n            Point3d p = _point.ConvertTo(coord);\n\n            string str = string.Format(\"Sphere: \") + nl;\n            str += string.Format(\"  Center -> ({0,10:g5}, {1,10:g5}, {2,10:g5})\", p.X, p.Y, p.Z) + nl;\n            str += string.Format(\"  Radius -> {0,10:g5}\", _r);\n            return str;\n        }\n\n        // Operators overloads\n        //-----------------------------------------------------------------\n\n        public static bool operator ==(Sphere s1, Sphere s2)\n        {\n            if (object.ReferenceEquals(s1, null))\n                return object.ReferenceEquals(s2, null);\n            return s1.Equals(s2);\n        }\n        public static bool operator !=(Sphere s1, Sphere s2)\n        {\n            if (object.ReferenceEquals(s1, null))\n                return !object.ReferenceEquals(s2, null);\n            return !s1.Equals(s2);\n        }\n\n    }\n}\n\n"
  },
  {
    "path": "GeometRi/Tetrahedron.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Text;\nusing static System.Math;\n\nnamespace GeometRi\n{\n    /// <summary>\n    /// Tetrahedron in 3D space defined by four points.\n    /// </summary>\n#if NET20_OR_GREATER\n    [Serializable]\n#endif\n    public class Tetrahedron : FiniteObject, IFiniteObject\n    {\n\n        private Point3d[] vertices;\n\n        private Coord3d _local_coord = null;\n        private AABB _aabb = null;\n\n        private List<Triangle> _list_t = null;\n        private List<Segment3d> _list_e = null;\n\n        #region \"Constructors\"\n        /// <summary>\n        /// Regular tetrahedron with vertices (0, 0, 0), (0, 1, 1), (1, 0, 1), (1, 1, 0)\n        /// </summary>\n        public Tetrahedron()\n        {\n            this.vertices = new Point3d[4];\n            vertices[0] = new Point3d(0, 0, 0);\n            vertices[1] = new Point3d(0, 1, 1);\n            vertices[2] = new Point3d(1, 0, 1);\n            vertices[3] = new Point3d(1, 1, 0);\n        }\n\n        /// <summary>\n        /// General tetrahedron defined by four points\n        /// </summary>\n        public Tetrahedron(Point3d v1, Point3d v2, Point3d v3, Point3d v4)\n        {\n            this.vertices = new Point3d[4];\n            vertices[0] = v1;\n            vertices[1] = v2;\n            vertices[2] = v3;\n            vertices[3] = v4;\n        }\n\n        /// <summary>\n        /// Random tetrahedron in unit cube.\n        /// </summary>\n        static public Tetrahedron Random()\n        {\n            Random rnd = new Random(Guid.NewGuid().GetHashCode());\n            Point3d p1 = new Point3d(rnd.NextDouble(), rnd.NextDouble(), rnd.NextDouble());\n            Point3d p2 = new Point3d(rnd.NextDouble(), rnd.NextDouble(), rnd.NextDouble());\n            Point3d p3 = new Point3d(rnd.NextDouble(), rnd.NextDouble(), rnd.NextDouble());\n            Point3d p4 = new Point3d(rnd.NextDouble(), rnd.NextDouble(), rnd.NextDouble());\n            return new Tetrahedron(p1, p2, p3, p4);\n        }\n\n        /// <summary>\n        /// Convert ConvexPolyhedron to Tetrahedron\n        /// </summary>\n        static public Tetrahedron FromConvexPolyhedron(ConvexPolyhedron cp)\n        {\n            if (cp.numVertices == 4 && cp.numFaces == 4 && cp.numEdges == 6)\n            {\n                return new Tetrahedron(cp.vertex[0], cp.vertex[1], cp.vertex[2], cp.vertex[3]);\n            }\n            else\n            {\n                throw new ArgumentException();\n            }\n        }\n        #endregion\n\n        /// <summary>\n        /// Creates copy of the object\n        /// </summary>\n        public Tetrahedron Copy()\n        {\n            return new Tetrahedron(vertices[0], vertices[1], vertices[2], vertices[3]);\n        }\n\n\n        #region \"Properties\"\n\n        /// <summary>\n        /// Center of tetrahedron\n        /// </summary>\n        public Point3d Center\n        {\n            get \n            {\n                return 0.25 * (vertices[0] + vertices[1] + vertices[2] + vertices[3]);\n            }\n\n        }\n\n        /// <summary>\n        /// Vertex of tetrahedron\n        /// </summary>\n        public Point3d A\n        {\n            get\n            {\n                return vertices[0];\n            }\n        }\n\n        /// <summary>\n        /// Vertex of tetrahedron\n        /// </summary>\n        public Point3d B\n        {\n            get\n            {\n                return vertices[1];\n            }\n        }\n\n        /// <summary>\n        /// Vertex of tetrahedron\n        /// </summary>\n        public Point3d C\n        {\n            get\n            {\n                return vertices[2];\n            }\n        }\n\n        /// <summary>\n        /// Vertex of tetrahedron\n        /// </summary>\n        public Point3d D\n        {\n            get\n            {\n                return vertices[3];\n            }\n        }\n\n        /// <summary>\n        /// List of faces forming the tetrahedron\n        /// </summary>\n        public List<Triangle> ListOfFaces\n        {\n            get\n            {\n                if (_list_t == null)\n                {\n                    _list_t = new List<Triangle> { };\n                    _list_t.Add(new Triangle(vertices[0], vertices[1], vertices[2]));\n                    _list_t.Add(new Triangle(vertices[0], vertices[3], vertices[1]));\n                    _list_t.Add(new Triangle(vertices[1], vertices[3], vertices[2]));\n                    _list_t.Add(new Triangle(vertices[2], vertices[3], vertices[0]));\n\n                    return _list_t;\n                }\n                else\n                {\n                    return _list_t;\n                }\n            }\n        }\n\n\n        /// <summary>\n        /// List of edges forming the tetragedron\n        /// </summary>\n        public List<Segment3d> ListOfEdges\n        {\n            get\n            {\n                if (_list_e == null)\n                {\n                    _list_e = new List<Segment3d> { };\n                    _list_e.Add(new Segment3d(vertices[0], vertices[1]));\n                    _list_e.Add(new Segment3d(vertices[1], vertices[2]));\n                    _list_e.Add(new Segment3d(vertices[2], vertices[0]));\n                    _list_e.Add(new Segment3d(vertices[0], vertices[3]));\n                    _list_e.Add(new Segment3d(vertices[1], vertices[3]));\n                    _list_e.Add(new Segment3d(vertices[2], vertices[3]));\n                    return _list_e;\n                }\n                else\n                {\n                    return _list_e;\n                }\n            }\n        }\n\n        /// <summary>\n        /// Volume of the tetrahedron.\n        /// </summary>\n        public double Volume\n        {\n            get \n            {\n                Vector3d a = new Vector3d(vertices[3], vertices[0]);\n                Vector3d b = new Vector3d(vertices[3], vertices[1]);\n                Vector3d c = new Vector3d(vertices[3], vertices[2]);\n                return Abs(a*(b.Cross(c))) / 6;\n            }\n        }\n\n        /// <summary>\n        /// Surface area of the tetrahedron.\n        /// </summary>\n        public double Area\n        {\n            get\n            {\n                double area = 0.0;\n                foreach (Triangle t in ListOfFaces)\n                {\n                    area += t.Area;\n                }\n                return area;\n            }\n        }\n\n        #endregion\n\n        #region \"BoundingBox\"\n        /// <summary>\n        /// Return minimum bounding box.\n        /// </summary>\n        public Box3d MinimumBoundingBox\n        {\n            get\n            {\n                throw new NotImplementedException();\n            }\n        }\n\n        /// <summary>\n        /// Return Bounding Box in given coordinate system.\n        /// </summary>\n        public Box3d BoundingBox(Coord3d coord = null)\n        {\n            return Box3d.BoundingBox(vertices, coord);\n        }\n\n        /// <summary>\n        /// Return Axis Aligned Bounding Box (AABB).\n        /// </summary>\n        public AABB AABB()\n        {\n            if (_aabb == null)\n            {\n                _aabb = GeometRi.AABB.BoundingBox(vertices);\n            }\n            return _aabb;\n        }\n\n        /// <summary>\n        /// Return bounding sphere.\n        /// </summary>\n        public Sphere BoundingSphere\n        {\n            get \n            { \n                throw new NotImplementedException();\n            }\n\n        }\n        #endregion\n\n        #region \"Distance\"\n\n        /// <summary>\n        /// Distance from tetrahedron to point (zero will be returned for point located inside box)\n        /// </summary>\n        public double DistanceTo(Point3d p)\n        {\n            return ClosestPoint(p).DistanceTo(p);\n        }\n\n        /// <summary>\n        /// Point on tetrahedron (including interior points) closest to target point \"p\".\n        /// </summary>\n        public Point3d ClosestPoint(Point3d p)\n        {\n            if (p.BelongsTo(this))\n            {\n                return p.Copy();\n            }\n            Point3d closest_point = null;\n            double dist = double.PositiveInfinity;\n\n            foreach (Triangle t in this.ListOfFaces)\n            {\n                Point3d temp_point = t.ClosestPoint(p);\n                double temp_dist = p.DistanceTo(temp_point);\n                if (temp_dist < dist)\n                {\n                    dist = temp_dist;\n                    closest_point = temp_point;\n                }\n            }\n            return closest_point;\n        }\n\n        /// <summary>\n        /// Distance between two tetrahedrones\n        /// </summary>\n        public double DistanceTo(Tetrahedron t)\n        {\n            if (t.A.BelongsTo(this) || t.B.BelongsTo(this) || t.C.BelongsTo(this) || t.D.BelongsTo(this))\n            {\n                return 0;\n            }\n            if (this.A.BelongsTo(t) || this.B.BelongsTo(t) || this.C.BelongsTo(t) || this.D.BelongsTo(t))\n            {\n                return 0;\n            }\n            double dist = double.PositiveInfinity;\n            foreach (Triangle t1 in this.ListOfFaces)\n            {\n                foreach (Segment3d t2 in t.ListOfEdges)\n                {\n                    double temp_dist = t1.DistanceTo(t2);\n                    if (temp_dist == 0.0)\n                    {\n                        return 0;\n                    } else if (temp_dist < dist)\n                    {\n                        dist = temp_dist;\n                    }\n                }\n            }\n            foreach (Triangle t1 in t.ListOfFaces)\n            {\n                foreach (Segment3d t2 in this.ListOfEdges)\n                {\n                    double temp_dist = t1.DistanceTo(t2);\n                    if (temp_dist == 0.0)\n                    {\n                        return 0;\n                    }\n                    else if (temp_dist < dist)\n                    {\n                        dist = temp_dist;\n                    }\n                }\n            }\n            return dist;\n        }\n\n        #endregion\n\n        #region \"Intersection\"\n\n        /// <summary>\n        /// Check intersection of two tetrahedrons\n        /// </summary>\n        public bool Intersects(Tetrahedron t)\n        {\n            if (!this.BoundingBox().Intersects(t.BoundingBox()))\n            {\n                return false;\n            }\n\n            if (t.A.BelongsTo(this) || t.B.BelongsTo(this) || t.C.BelongsTo(this) || t.D.BelongsTo(this))\n            {\n                return true;\n            }\n\n            foreach (Triangle bt in this.ListOfFaces)\n            {\n                if (bt.Intersects(t)) return true;\n            }\n\n            return false;\n        }\n\n        /// <summary>\n        /// Check intersection of two tetrahedrons\n        /// </summary>\n        public bool IntersectsFast(Tetrahedron t)\n        {\n            // From \"Intersection of Convex Objects: The Method of Separating Axes\"\n            // by David Eberly, Geometric Tools, Redmond WA 98052, https://www.geometrictools.com/\n            // https://www.geometrictools.com/Documentation/MethodOfSeparatingAxes.pdf\n            // Licensed under the Creative Commons Attribution 4.0 International License\n\n            throw new NotImplementedException();\n        }\n\n        /// <summary>\n        /// Check intersection of tetrahedron with triangle\n        /// </summary>\n        public bool Intersects(Triangle t)\n        {\n            if (t.A.BelongsTo(this) || t.B.BelongsTo(this) || t.C.BelongsTo(this))\n            {\n                return true;\n            }\n\n            foreach (Triangle bt in this.ListOfFaces)\n            {\n                if (bt.Intersects(t)) return true;\n            }\n\n            return false;\n        }\n\n        /// <summary>\n        /// Check intersection of tetrahedron with line\n        /// </summary>\n        public bool Intersects(Line3d l)\n        {\n            foreach (Triangle bt in this.ListOfFaces)\n            {\n                if (l.IntersectionWith(bt) != null) return true;\n            }\n            return false;\n        }\n\n        /// <summary>\n        /// Check intersection of tetrahedron with ray\n        /// </summary>\n        public bool Intersects(Ray3d r)\n        {\n            foreach (Triangle bt in this.ListOfFaces)\n            {\n                if (r.IntersectionWith(bt) != null) return true;\n            }\n            return false;\n        }\n\n        /// <summary>\n        /// Check intersection of tetrahedron with segment\n        /// </summary>\n        public bool Intersects(Segment3d s)\n        {\n            if (s.P1.BelongsTo(this) || s.P2.BelongsTo(this))\n            {\n                return true;\n            }\n            foreach (Triangle bt in this.ListOfFaces)\n            {\n                if (s.IntersectionWith(bt) != null) return true;\n            }\n            return false;\n        }\n\n        /// <summary>\n        /// Check intersection of tetrahedron with box\n        /// </summary>\n        public bool Intersects(Box3d box)\n        {\n            if (!this.BoundingBox().Intersects(box))\n            {\n                return false;\n            }\n            foreach (Triangle face in this.ListOfFaces)\n            {\n                if (face.Intersects(box)) return true;\n            }\n            return false;\n        }\n\n        /// <summary>\n        /// Check intersection of tetrahedron with sphere\n        /// </summary>\n        public bool Intersects(Sphere s)\n        {\n            if (!this.BoundingBox().Intersects(s.BoundingBox()))\n            {\n                return false;\n            }\n            foreach (Triangle face in this.ListOfFaces)\n            {\n                if (face.Intersects(s)) return true;\n            }\n            return false;\n        }\n\n        /// <summary>\n        /// Get intersection of line with tetrahedron.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'.\n        /// </summary>\n        public object IntersectionWith(Line3d l)\n        {\n            throw new NotImplementedException();\n        }\n\n        #endregion\n\n        internal override int _PointLocation(Point3d p)\n        {\n\n            int v1 = _SameSide(vertices[0], vertices[1], vertices[2], vertices[3], p);\n            int v2 = _SameSide(vertices[1], vertices[2], vertices[3], vertices[0], p);\n            int v3 = _SameSide(vertices[2], vertices[3], vertices[0], vertices[1], p);\n            int v4 = _SameSide(vertices[3], vertices[0], vertices[1], vertices[2], p);\n\n            int sum = v1 + v2 + v3 + v4;\n            int product = v1 * v2 * v3 * v4;\n\n            if (sum == 4)\n            {\n                return 1; // Point is strictly inside tetrahedron\n            }\n            else if (product == 0 && sum < 4)\n            {\n                return 0; // Point is on boundary\n            }\n            else\n            {\n                return -1; // Point is outside\n            }\n        }\n\n        internal int _SameSide(Point3d a, Point3d b, Point3d c, Point3d d, Point3d p)\n        {\n            Vector3d normal = (b - a).ToVector.Cross((c - a).ToVector);\n            double dot_d = normal * (d - a).ToVector;\n            double dot_p = normal * (p - a).ToVector;\n            if (GeometRi3D.AlmostEqual(dot_p,0.0))\n            {\n                return 0; // Point is on face\n            }\n            else if (Sign(dot_d) == Sign(dot_p))\n            {\n                return 1; // points are on the same side\n            } else\n            {\n                return 999;\n            }\n        }\n\n        internal int _WhichSide(Tetrahedron tetra, Point3d p, Vector3d d)\n        {\n            // From \"Intersection of Convex Objects: The Method of Separating Axes\"\n            // by David Eberly, Geometric Tools, Redmond WA 98052, https://www.geometrictools.com/\n            // https://www.geometrictools.com/Documentation/MethodOfSeparatingAxes.pdf\n            // Licensed under the Creative Commons Attribution 4.0 International License\n\n            int positive = 0;\n            int negative = 0;\n\n            for (int i = 0; i <= 3; i++)\n            {\n                double t = d * (tetra.vertices[i] - p).ToVector;\n                if (t>0)\n                {\n                    positive++;\n                }\n                if (t<0)\n                {\n                    negative++;\n                }\n                if (positive > 0 && negative >0)\n                {\n                    // this is not separating axis\n                    return 0; \n                }\n            }\n\n            return positive > 0 ? +1 : -1;\n        }\n\n\n        /// <summary>\n        /// Check if tetrahedron is located inside box with tolerance defined by global tolerance property (GeometRi3D.Tolerance).\n        /// </summary>\n        public bool IsInside(Box3d box)\n        {\n            // Relative tolerance ================================\n            if (!GeometRi3D.UseAbsoluteTolerance)\n            {\n                double tol = GeometRi3D.Tolerance;\n                GeometRi3D.Tolerance = tol * Sqrt(Max(this.A.DistanceSquared(this.D),Max(this.A.DistanceSquared(this.B), this.A.DistanceSquared(this.C))));\n                GeometRi3D.UseAbsoluteTolerance = true;\n                bool result = this.IsInside(box);\n                GeometRi3D.UseAbsoluteTolerance = false;\n                GeometRi3D.Tolerance = tol;\n                return result;\n            }\n            //====================================================\n\n            if (!this.A.IsInside(box)) return false;\n            if (!this.B.IsInside(box)) return false;\n            if (!this.C.IsInside(box)) return false;\n            if (!this.D.IsInside(box)) return false;\n\n            return true;\n        }\n\n\n        #region \"TranslateRotateReflect\"\n        /// <summary>\n        /// Translate tetrahedron by a vector\n        /// </summary>\n        public Tetrahedron Translate(Vector3d v)\n        {\n            return new Tetrahedron(vertices[0].Translate(v), vertices[1].Translate(v), vertices[2].Translate(v), vertices[3].Translate(v));\n        }\n\n        /// <summary>\n        /// Rotate tetrahedron around point 'p' as a rotation center.\n        /// </summary>\n        public Tetrahedron Rotate(Rotation r, Point3d p)\n        {\n            Point3d p1 = r.ToRotationMatrix * (vertices[0] - p) + p;\n            Point3d p2 = r.ToRotationMatrix * (vertices[1] - p) + p;\n            Point3d p3 = r.ToRotationMatrix * (vertices[2] - p) + p;\n            Point3d p4 = r.ToRotationMatrix * (vertices[3] - p) + p;\n            return new Tetrahedron(p1, p2, p3, p4);\n        }\n\n        /// <summary>\n        /// Reflect tetrahedron in given point\n        /// </summary>\n        public virtual Tetrahedron ReflectIn(Point3d p)\n        {\n            Point3d p1 = vertices[0].ReflectIn(p);\n            Point3d p2 = vertices[1].ReflectIn(p);\n            Point3d p3 = vertices[2].ReflectIn(p);\n            Point3d p4 = vertices[3].ReflectIn(p);\n            return new Tetrahedron(p1, p2, p3, p4);\n        }\n\n        /// <summary>\n        /// Reflect tetrahedron in given line\n        /// </summary>\n        public virtual Tetrahedron ReflectIn(Line3d l)\n        {\n            Point3d p1 = vertices[0].ReflectIn(l);\n            Point3d p2 = vertices[1].ReflectIn(l);\n            Point3d p3 = vertices[2].ReflectIn(l);\n            Point3d p4 = vertices[3].ReflectIn(l);\n            return new Tetrahedron(p1, p2, p3, p4);\n        }\n\n        /// <summary>\n        /// Reflect tetrahedron in given plane\n        /// </summary>\n        public virtual Tetrahedron ReflectIn(Plane3d s)\n        {\n            Point3d p1 = vertices[0].ReflectIn(s);\n            Point3d p2 = vertices[1].ReflectIn(s);\n            Point3d p3 = vertices[2].ReflectIn(s);\n            Point3d p4 = vertices[3].ReflectIn(s);\n            return new Tetrahedron(p1, p2, p3, p4);\n        }\n\n        /// <summary>\n        /// Scale tetrahedron relative to center point\n        /// </summary>\n        public virtual Tetrahedron Scale(double scale)\n        {\n            Point3d center = this.Center;\n            Point3d p1 = center + scale * (vertices[0] - center);\n            Point3d p2 = center + scale * (vertices[1] - center);\n            Point3d p3 = center + scale * (vertices[2] - center);\n            Point3d p4 = center + scale * (vertices[3] - center);\n            return new Tetrahedron(p1, p2, p3, p4);\n        }\n\n        /// <summary>\n        /// Scale tetrahedron relative to given point\n        /// </summary>\n        public virtual Tetrahedron Scale(double scale, Point3d scaling_center)\n        {\n            Point3d p1 = scaling_center + scale * (vertices[0] - scaling_center);\n            Point3d p2 = scaling_center + scale * (vertices[1] - scaling_center);\n            Point3d p3 = scaling_center + scale * (vertices[2] - scaling_center);\n            Point3d p4 = scaling_center + scale * (vertices[3] - scaling_center);\n            return new Tetrahedron(p1, p2, p3, p4);\n        }\n\n        /// <summary>\n        /// Scale tetrahedron\n        /// </summary>\n        public virtual Tetrahedron Scale(double scale_x, double scale_y, double scale_z)\n        {\n            Point3d center = this.Center;\n            Matrix3d m = Matrix3d.DiagonalMatrix(scale_x, scale_y, scale_z);\n            Point3d p1 = center.Translate(m * (vertices[0] - center).ToVector);\n            Point3d p2 = center.Translate(m * (vertices[1] - center).ToVector);\n            Point3d p3 = center.Translate(m * (vertices[2] - center).ToVector);\n            Point3d p4 = center.Translate(m * (vertices[3] - center).ToVector);\n            return new Tetrahedron(p1, p2, p3, p4);\n        }\n        #endregion\n\n        /// <summary>\n        /// Determines whether two objects are equal.\n        /// </summary>\n        public override bool Equals(object obj)\n        {\n            if (obj == null || (!object.ReferenceEquals(this.GetType(), obj.GetType())))\n            {\n                return false;\n            }\n            Tetrahedron t = (Tetrahedron)obj;\n\n            if (GeometRi3D.UseAbsoluteTolerance)\n            {\n                int count = 0;\n                foreach (Point3d p1 in this.vertices)\n                {\n                    foreach (Point3d p2 in t.vertices)\n                    {\n                        if (p1 == p2)\n                        {\n                            count++;\n                        }\n                    }\n                }\n                if (count == 4) return true;\n                return false;\n            }\n            else\n            {\n                double tol = GeometRi3D.Tolerance;\n                GeometRi3D.Tolerance = tol * this.A.DistanceTo(this.B);\n                GeometRi3D.UseAbsoluteTolerance = true;\n                bool result = this.Equals(t);\n                GeometRi3D.UseAbsoluteTolerance = false;\n                GeometRi3D.Tolerance = tol;\n                return result;\n            }\n\n        }\n\n        /// <summary>\n        /// Returns the hashcode for the object.\n        /// </summary>\n        public override int GetHashCode()\n        {\n            return GeometRi3D.HashFunction(vertices[0].GetHashCode(), vertices[1].GetHashCode(), vertices[2].GetHashCode(), vertices[3].GetHashCode());\n        }\n\n        /// <summary>\n        /// String representation of an object in global coordinate system.\n        /// </summary>\n        public override string ToString()\n        {\n            return ToString(Coord3d.GlobalCS);\n        }\n\n        /// <summary>\n        /// String representation of an object in global coordinate system.\n        /// </summary>\n        public string ToString(bool full_precision = false)\n        {\n            return ToString(Coord3d.GlobalCS, full_precision);\n        }\n\n        /// <summary>\n        /// String representation of an object in reference coordinate system.\n        /// </summary>\n        public string ToString(Coord3d coord, bool full_precision = false)\n        {\n            string nl = System.Environment.NewLine;\n\n            if (coord == null) { coord = Coord3d.GlobalCS; }\n            Point3d p1 = vertices[0].ConvertTo(coord);\n            Point3d p2 = vertices[1].ConvertTo(coord);\n            Point3d p3 = vertices[2].ConvertTo(coord);\n            Point3d p4 = vertices[3].ConvertTo(coord);\n\n            string str = string.Format(\"Tetrahedron (reference coord.sys. \") + coord.Name + \"):\" + nl;\n            if (full_precision)\n            {\n                str += string.Format(\"A -> ({0}, {1}, {2})\", p1.X, p1.Y, p1.Z) + nl;\n                str += string.Format(\"B -> ({0}, {1}, {2})\", p2.X, p2.Y, p2.Z) + nl;\n                str += string.Format(\"C -> ({0}, {1}, {2})\", p3.X, p3.Y, p3.Z) + nl;\n                str += string.Format(\"D -> ({0}, {1}, {2})\", p4.X, p4.Y, p4.Z);\n            }\n            else\n            {\n                str += string.Format(\"A -> ({0,10:g5}, {1,10:g5}, {2,10:g5})\", p1.X, p1.Y, p1.Z) + nl;\n                str += string.Format(\"B -> ({0,10:g5}, {1,10:g5}, {2,10:g5})\", p2.X, p2.Y, p2.Z) + nl;\n                str += string.Format(\"C -> ({0,10:g5}, {1,10:g5}, {2,10:g5})\", p3.X, p3.Y, p3.Z) + nl;\n                str += string.Format(\"D -> ({0,10:g5}, {1,10:g5}, {2,10:g5})\", p4.X, p4.Y, p4.Z);\n            }\n\n            return str;\n        }\n\n    }\n}\n"
  },
  {
    "path": "GeometRi/Triangle.cs",
    "content": "﻿using System;\nusing System.Security;\nusing static System.Math;\n\nnamespace GeometRi\n{\n    /// <summary>\n    /// Triangle in 3D space defined by three points.\n    /// </summary>\n#if NET20_OR_GREATER\n    [Serializable]\n#endif\n    public class Triangle : PlanarFiniteObject, IPlanarObject\n    {\n        private Point3d _a, _b, _c;\n        private double? _ab, _ac, _bc, _perimeter, _area;\n        private Vector3d _normal;\n        private Circle3d _circumcircle;\n        private double? _angleA, _angleB, _angleC;\n        private Plane3d _plane;\n\n        private bool HasChanged => _a.HasChanged || _b.HasChanged || _c.HasChanged;\n        private void CheckFields()\n        {\n            if (HasChanged)\n            {\n                _a = _a.Copy();\n                _b = _b.Copy();\n                _c = _c.Copy();\n                ClearCache();\n            }\n        }\n        private void ClearCache()\n        {\n            _ab = null;\n            _ac = null;\n            _bc = null;\n            _perimeter = null;\n            _area = null;\n            _normal = null;\n            _circumcircle = null;\n            _angleA = null;\n            _angleB = null;\n            _angleC = null;\n            _plane = null;\n        }\n\n        /// <summary>\n        /// Initializes triangle object using three points.\n        /// </summary>\n        public Triangle(Point3d A, Point3d B, Point3d C)\n        {\n            if (Point3d.CollinearPoints(A, B, C))\n            {\n                throw new Exception(\"Collinear points\");\n            }\n            _a = A.Copy();\n            _b = B.Copy();\n            _c = C.Copy();\n        }\n\n        /// <summary>\n        /// Creates copy of the object\n        /// </summary>\n        public Triangle Copy()\n        {\n            return new Triangle(_a, _b, _c);\n        }\n\n        #region \"Properties\"\n        /// <summary>\n        /// First point of triangle\n        /// </summary>\n        public Point3d A\n        {\n            get { return _a; }\n            set\n            {\n                if (Point3d.CollinearPoints(value, _b, _c))\n                {\n                    throw new Exception(\"Collinear points\");\n                }\n                _a = value.Copy();\n                ClearCache();\n            }\n        }\n\n        /// <summary>\n        /// Second point of triangle\n        /// </summary>\n        public Point3d B\n        {\n            get { return _b; }\n            set\n            {\n                if (Point3d.CollinearPoints(_a, value, _c))\n                {\n                    throw new Exception(\"Collinear points\");\n                }\n                _b = value.Copy();\n                ClearCache();\n            }\n        }\n\n        /// <summary>\n        /// Third point of triangle\n        /// </summary>\n        public Point3d C\n        {\n            get { return _c; }\n            set\n            {\n                if (Point3d.CollinearPoints(_a, _b, value))\n                {\n                    throw new Exception(\"Collinear points\");\n                }\n                _c = value.Copy();\n                ClearCache();\n            }\n        }\n\n        /// <summary>\n        /// Length of AB side\n        /// </summary>\n        public double AB\n        {\n            get\n            {\n                CheckFields();\n                if (_ab == null)\n                {\n                    _ab = _a.DistanceTo(_b);\n                }\n                return _ab.Value;\n            }\n        }\n\n        /// <summary>\n        /// Length of AC side\n        /// </summary>\n        public double AC\n        {\n            get\n            {\n                CheckFields();\n                if (_ac == null)\n                {\n                    _ac = _a.DistanceTo(_c);\n                }\n                return _ac.Value;\n            }\n        }\n\n        /// <summary>\n        /// Length of BC side\n        /// </summary>\n        public double BC\n        {\n            get\n            {\n                CheckFields();\n                if (_bc == null)\n                {\n                    _bc = _b.DistanceTo(_c);\n                }\n                return _bc.Value;\n            }\n        }\n\n        /// <summary>\n        /// Perimeter of the triangle\n        /// </summary>\n        public double Perimeter\n        {\n            get\n            {\n                CheckFields();\n                if (_perimeter == null)\n                {\n                    _perimeter = AB + BC + AC;\n                }\n                return _perimeter.Value;\n            }\n        }\n\n        /// <summary>\n        /// Area of the triangle\n        /// </summary>\n        public double Area\n        {\n            get\n            {\n                CheckFields();\n                if (_area == null)\n                {\n                    Vector3d v1 = new Vector3d(_a, _b);\n                    Vector3d v2 = new Vector3d(_a, _c);\n                    _area = 0.5 * v1.Cross(v2).Norm;\n                }\n                return _area.Value;\n            }\n        }\n\n        public Vector3d Normal\n        {\n            get\n            {\n                CheckFields();\n                if (_normal == null)\n                {\n                    _normal = new Vector3d(_a, _b).Cross(new Vector3d(_a, _c)).Normalized;\n                }\n                return _normal;\n            }\n        }\n\n        public bool IsOriented\n        {\n            get { return false; }\n        }\n\n        /// <summary>\n        /// Plane the triangle belongs to\n        /// </summary>\n        internal override Plane3d Plane\n        {\n            get\n            {\n                CheckFields();\n                if (_plane is null)\n                {\n                    _plane = new Plane3d(_a, Normal);\n                }\n                return _plane;\n            }\n        }\n\n        /// <summary>\n        /// Convert triangle to a new plane object.\n        /// </summary>\n        public Plane3d ToPlane\n        {\n            get\n            {\n                return Plane.Copy();\n            }\n        }\n\n        /// <summary>\n        /// Circumcircle of the triangle\n        /// </summary>\n        public Circle3d Circumcircle\n        {\n            get\n            {\n                CheckFields();\n                if (_circumcircle == null)\n                {\n                    _circumcircle = new Circle3d(_a, _b, _c);\n                }\n                return _circumcircle;\n            }\n        }\n\n        /// <summary>\n        /// Angle at the vertex A\n        /// </summary>\n        public double Angle_A\n        {\n            get\n            {\n                CheckFields();\n                if (_angleA == null)\n                {\n                    _angleA = new Vector3d(_a, _b).AngleTo(new Vector3d(_a, _c));\n                }\n                return _angleA.Value;\n            }\n        }\n\n        /// <summary>\n        /// Angle at the vertex B\n        /// </summary>\n        public double Angle_B\n        {\n            get\n            {\n                CheckFields();\n                if (_angleB == null)\n                {\n                    _angleB = new Vector3d(_b, _a).AngleTo(new Vector3d(_b, _c));\n                }\n                return _angleB.Value;\n            }\n        }\n\n        /// <summary>\n        /// Angle at the vertex C\n        /// </summary>\n        public double Angle_C\n        {\n            get\n            {\n                CheckFields();\n                if (_angleC == null)\n                {\n                    _angleC = new Vector3d(_c, _a).AngleTo(new Vector3d(_c, _b));\n                }\n                return _angleC.Value;\n            }\n        }\n\n        /// <summary>\n        /// Angle bisector at the vertex A\n        /// </summary>\n        public Segment3d Bisector_A\n        {\n            get\n            {\n                Point3d p = _b + (_c - _b) / (1 + AC / AB);\n                return new Segment3d(_a, p);\n            }\n        }\n\n        /// <summary>\n        /// Angle bisector at the vertex B\n        /// </summary>\n        public Segment3d Bisector_B\n        {\n            get\n            {\n                Point3d p = _c + (_a - _c) / (1 + AB / BC);\n                return new Segment3d(_b, p);\n            }\n        }\n\n        /// <summary>\n        /// Angle bisector at the vertex C\n        /// </summary>\n        public Segment3d Bisector_C\n        {\n            get\n            {\n                Point3d p = _a + (_b - _a) / (1 + BC / AC);\n                return new Segment3d(_c, p);\n            }\n        }\n\n        /// <summary>\n        /// External angle bisector at the vertex A\n        /// </summary>\n        public Line3d ExternalBisector_A\n        {\n            get\n            {\n                Point3d p = _a + (_a - _b);\n                return new Triangle(_a, p, _c).Bisector_A.ToLine;\n            }\n        }\n\n        /// <summary>\n        /// External angle bisector at the vertex B\n        /// </summary>\n        public Line3d ExternalBisector_B\n        {\n            get\n            {\n                Point3d p = _b + (_b - _a);\n                return new Triangle(_b, p, _c).Bisector_A.ToLine;\n            }\n        }\n\n        /// <summary>\n        /// External angle bisector at the vertex C\n        /// </summary>\n        public Line3d ExternalBisector_C\n        {\n            get\n            {\n                Point3d p = _c + (_c - _a);\n                return new Triangle(_c, p, _b).Bisector_A.ToLine;\n            }\n        }\n\n        /// <summary>\n        /// Incenter of the triangle\n        /// </summary>\n        public Point3d Incenter\n        {\n            get { return Bisector_A.Line.PerpendicularTo(Bisector_B.Line); }\n        }\n\n        /// <summary>\n        /// Centroid of the triangle\n        /// </summary>\n        public Point3d Centroid\n        {\n            get { return new Point3d((A.X + B.X + C.X) / 3, (A.Y + B.Y + C.Y) / 3, (A.Z + B.Z + C.Z) / 3); }\n        }\n\n        /// <summary>\n        /// Orthocenter of the triangle\n        /// </summary>\n        public Point3d Orthocenter\n        {\n            get { return Altitude_A.Line.PerpendicularTo(Altitude_B.Line); }\n        }\n\n        /// <summary>\n        /// Circumcenter of the triangle\n        /// </summary>\n        public Point3d Circumcenter\n        {\n            get { return new Circle3d(_a, _b, _c).Center; }\n        }\n\n        /// <summary>\n        /// Incircle of the triangle\n        /// </summary>\n        public Circle3d Incircle\n        {\n            get\n            {\n                Point3d p = Bisector_A.Line.PerpendicularTo(Bisector_B.Line);\n                double r = 2 * Area / Perimeter;\n                Vector3d v = new Vector3d(_a, _b).Cross(new Vector3d(_a, _c));\n                return new Circle3d(p, r, v);\n            }\n        }\n\n        /// <summary>\n        /// Altitude at the vertex A\n        /// </summary>\n        public Segment3d Altitude_A\n        {\n            get\n            {\n                Point3d p = _a.ProjectionTo(new Line3d(_b, _c));\n                return new Segment3d(_a, p);\n            }\n        }\n\n        /// <summary>\n        /// Altitude at the vertex B\n        /// </summary>\n        public Segment3d Altitude_B\n        {\n            get\n            {\n                Point3d p = _b.ProjectionTo(new Line3d(_a, _c));\n                return new Segment3d(_b, p);\n            }\n        }\n\n        /// <summary>\n        /// Altitude at the vertex C\n        /// </summary>\n        public Segment3d Altitude_C\n        {\n            get\n            {\n                Point3d p = _c.ProjectionTo(new Line3d(_a, _b));\n                return new Segment3d(_c, p);\n            }\n        }\n\n        /// <summary>\n        /// Median at the vertex A\n        /// </summary>\n        public Segment3d Median_A\n        {\n            get { return new Segment3d(_a, (_b + _c) / 2); }\n        }\n\n        /// <summary>\n        /// Median at the vertex B\n        /// </summary>\n        public Segment3d Median_B\n        {\n            get { return new Segment3d(_b, (_a + _c) / 2); }\n        }\n\n        /// <summary>\n        /// Median at the vertex C\n        /// </summary>\n        public Segment3d Median_C\n        {\n            get { return new Segment3d(_c, (_a + _b) / 2); }\n        }\n        #endregion\n\n        #region \"TriangleProperties\"\n        /// <summary>\n        /// True if all sides of the triangle are the same length\n        /// </summary>\n        public bool IsEquilateral\n        {\n            get { return GeometRi3D.AlmostEqual(AB, AC) && GeometRi3D.AlmostEqual(AB, BC); }\n        }\n\n        /// <summary>\n        /// True if two sides of the triangle are the same length\n        /// </summary>\n        public bool IsIsosceles\n        {\n            get { return GeometRi3D.AlmostEqual(AB, AC) || GeometRi3D.AlmostEqual(AB, BC) || GeometRi3D.AlmostEqual(AC, BC); }\n        }\n\n        /// <summary>\n        /// True if all sides are unequal\n        /// </summary>\n        public bool IsScalene\n        {\n            get { return GeometRi3D.NotEqual(AB, AC) && GeometRi3D.NotEqual(AB, BC) && GeometRi3D.NotEqual(AC, BC); }\n        }\n\n        /// <summary>\n        /// True if one angle is equal 90 degrees\n        /// </summary>\n        public bool IsRight\n        {\n            get { return GeometRi3D.AlmostEqual(Angle_A, PI / 2) || GeometRi3D.AlmostEqual(Angle_B, PI / 2) || GeometRi3D.AlmostEqual(Angle_C, PI / 2); }\n        }\n\n        /// <summary>\n        /// True if one angle is greater than 90 degrees\n        /// </summary>\n        public bool IsObtuse\n        {\n            get { return GeometRi3D.Greater(Angle_A, PI / 2) || GeometRi3D.Greater(Angle_B, PI / 2) || GeometRi3D.Greater(Angle_C, PI / 2); }\n        }\n\n        /// <summary>\n        /// True if all angles are less than 90 degrees\n        /// </summary>\n        public bool IsAcute\n        {\n            get { return GeometRi3D.Smaller(Angle_A, PI / 2) && GeometRi3D.Smaller(Angle_B, PI / 2) && GeometRi3D.Smaller(Angle_C, PI / 2); }\n        }\n        #endregion\n\n        #region \"ParallelMethods\"\n        /// <summary>\n        /// Check if two objects are parallel\n        /// </summary>\n        public bool IsParallelTo(ILinearObject obj)\n        {\n            return this.Normal.IsOrthogonalTo(obj.Direction);\n        }\n\n        /// <summary>\n        /// Check if two objects are NOT parallel\n        /// </summary>\n        public bool IsNotParallelTo(ILinearObject obj)\n        {\n            return !this.Normal.IsOrthogonalTo(obj.Direction);\n        }\n\n        /// <summary>\n        /// Check if two objects are orthogonal\n        /// </summary>\n        public bool IsOrthogonalTo(ILinearObject obj)\n        {\n            return this.Normal.IsParallelTo(obj.Direction);\n        }\n\n        /// <summary>\n        /// Check if two objects are parallel\n        /// </summary>\n        public bool IsParallelTo(IPlanarObject obj)\n        {\n            return this.Normal.IsParallelTo(obj.Normal);\n        }\n\n        /// <summary>\n        /// Check if two objects are NOT parallel\n        /// </summary>\n        public bool IsNotParallelTo(IPlanarObject obj)\n        {\n            return this.Normal.IsNotParallelTo(obj.Normal);\n        }\n\n        /// <summary>\n        /// Check if two objects are orthogonal\n        /// </summary>\n        public bool IsOrthogonalTo(IPlanarObject obj)\n        {\n            return this.Normal.IsOrthogonalTo(obj.Normal);\n        }\n\n        /// <summary>\n        /// Check if two objects are coplanar\n        /// </summary>\n        public bool IsCoplanarTo(IPlanarObject obj)\n        {\n            return GeometRi3D._coplanar(this, obj);\n        }\n\n        /// <summary>\n        /// Check if two objects are coplanar\n        /// </summary>\n        public bool IsCoplanarTo(ILinearObject obj)\n        {\n            return GeometRi3D._coplanar(this, obj);\n        }\n        #endregion\n\n        #region \"BoundingBox\"\n        /// <summary>\n        /// Return minimum bounding box.\n        /// </summary>\n        public Box3d MinimumBoundingBox\n        {\n            get\n            {\n                double s1, s2, s3;\n                s1 = AB * Altitude_C.Length;\n                s2 = BC * Altitude_A.Length;\n                s3 = AC * Altitude_B.Length;\n\n                if (s1 <= s2 && s1 <= s3)\n                {\n                    Vector3d v1 = new Vector3d(_a, _b);\n                    Vector3d v2 = new Vector3d(_a, _c);\n                    Coord3d coord = new Coord3d(_a, v1, v2);\n                    return this.BoundingBox(coord);\n                }\n                else if (s2 <= s3)\n                {\n                    Vector3d v1 = new Vector3d(_b, _c);\n                    Vector3d v2 = new Vector3d(_b, _a);\n                    Coord3d coord = new Coord3d(_b, v1, v2);\n                    return this.BoundingBox(coord);\n                }\n                else\n                {\n                    Vector3d v1 = new Vector3d(_a, _c);\n                    Vector3d v2 = new Vector3d(_a, _b);\n                    Coord3d coord = new Coord3d(_a, v1, v2);\n                    return this.BoundingBox(coord);\n                }\n            }\n        }\n\n        /// <summary>\n        /// Return Bounding Box in given coordinate system.\n        /// </summary>\n        public Box3d BoundingBox(Coord3d coord = null)\n        {\n            coord = (coord == null) ? Coord3d.GlobalCS : coord;\n            Line3d l1 = new Line3d(coord.Origin, coord.Xaxis);\n            Line3d l2 = new Line3d(coord.Origin, coord.Yaxis);\n            Line3d l3 = new Line3d(coord.Origin, coord.Zaxis);\n\n            double px, py, pz, lx, ly, lz;\n            Segment3d s = this.ProjectionTo(l1);\n            px = (0.5 * (s.P1 + s.P2)).ConvertTo(coord).X;\n            lx = s.Length;\n            s = this.ProjectionTo(l2);\n            py = (0.5 * (s.P1 + s.P2)).ConvertTo(coord).Y;\n            ly = s.Length;\n            s = this.ProjectionTo(l3);\n            pz = (0.5 * (s.P1 + s.P2)).ConvertTo(coord).Z;\n            lz = s.Length;\n\n            return new Box3d(new Point3d(px, py, pz, coord), lx, ly, lz, coord);\n        }\n\n        /// <summary>\n        /// Return Axis Aligned Bounding Box (AABB).\n        /// </summary>\n        public AABB AABB()\n        {\n            return GeometRi.AABB.BoundingBox(new Point3d[] { A, B, C });\n        }\n\n        /// <summary>\n        /// Return bounding sphere.\n        /// </summary>\n        public Sphere BoundingSphere\n        {\n            get { return new Sphere(Circumcenter, Circumcenter.DistanceTo(_a)); }\n        }\n        #endregion\n\n        #region \"Distance\"\n        /// <summary>\n        /// Shortest distance between triangle and point\n        /// </summary>\n        public double DistanceTo(Point3d p)\n        {\n            return Sqrt(this.DistanceSquared(p));\n        }\n\n        /// <summary>\n        /// Shortest distance between triangle and point\n        /// </summary>\n        public double DistanceTo(Point3d p, out Point3d closest_point)\n        {\n            Point3d projection_point = p.ProjectionTo(this.Plane);\n\n            // Check if projection point is outside\n            if (new Vector3d(_a, _b).Cross(new Vector3d(_a, projection_point)).Dot(this._normal) < 0)\n            {\n                if (new Vector3d(_b, _c).Cross(new Vector3d(_b, projection_point)).Dot(this._normal) < 0)\n                {\n                    double dist1 = p.DistanceTo(new Segment3d(_a, _b), out closest_point);\n                    double dist2 = p.DistanceTo(new Segment3d(_b, _c), out Point3d cp2);\n                    if (dist1 < dist2)\n                    {\n                        return dist1;\n                    }\n                    else\n                    {\n                        closest_point = cp2;\n                        return dist2;\n                    }\n                }\n                if (new Vector3d(_c, _a).Cross(new Vector3d(_c, projection_point)).Dot(this._normal) < 0)\n                {\n                    double dist1 = p.DistanceTo(new Segment3d(_a, _b), out closest_point);\n                    double dist2 = p.DistanceTo(new Segment3d(_c, _a), out Point3d cp2);\n                    if (dist1 < dist2)\n                    {\n                        return dist1;\n                    }\n                    else\n                    {\n                        closest_point = cp2;\n                        return dist2;\n                    }\n                }\n                return p.DistanceTo(new Segment3d(_a, _b), out closest_point);\n            }\n            if (new Vector3d(_b, _c).Cross(new Vector3d(_b, projection_point)).Dot(this._normal) < 0)\n            {\n                if (new Vector3d(_c, _a).Cross(new Vector3d(_c, projection_point)).Dot(this._normal) < 0)\n                {\n                    double dist1 = p.DistanceTo(new Segment3d(_b, _c), out closest_point);\n                    double dist2 = p.DistanceTo(new Segment3d(_c, _a), out Point3d cp2);\n                    if (dist1 < dist2)\n                    {\n                        return dist1;\n                    }\n                    else\n                    {\n                        closest_point = cp2;\n                        return dist2;\n                    }\n                }\n                return p.DistanceTo(new Segment3d(_b, _c), out closest_point);\n            }\n            if (new Vector3d(_c, _a).Cross(new Vector3d(_c, projection_point)).Dot(this._normal) < 0)\n            {\n                return p.DistanceTo(new Segment3d(_c, _a), out closest_point);\n            }\n\n            // Projection point is inside\n            closest_point = projection_point;\n            return p.DistanceTo(projection_point);\n        }\n\n        public double DistanceSquared(Point3d p)\n        {\n            Point3d projection_point = p.ProjectionTo(this.Plane);\n\n            // Check if projection point is outside\n            if (new Vector3d(_a, _b).Cross(new Vector3d(_a, projection_point)).Dot(this._normal) < 0)\n            {\n                if (new Vector3d(_b, _c).Cross(new Vector3d(_b, projection_point)).Dot(this._normal) < 0)\n                {\n                    return Min(p.DistanceSquared(new Segment3d(_a, _b)), p.DistanceSquared(new Segment3d(_b, _c)));\n                }\n                if (new Vector3d(_c, _a).Cross(new Vector3d(_c, projection_point)).Dot(this._normal) < 0)\n                {\n                    return Min(p.DistanceSquared(new Segment3d(_a, _b)), p.DistanceSquared(new Segment3d(_c, _a)));\n                }\n                return p.DistanceSquared(new Segment3d(_a, _b));\n            }\n            if (new Vector3d(_b, _c).Cross(new Vector3d(_b, projection_point)).Dot(this._normal) < 0)\n            {\n                if (new Vector3d(_c, _a).Cross(new Vector3d(_c, projection_point)).Dot(this._normal) < 0)\n                {\n                    return Min(p.DistanceSquared(new Segment3d(_b, _c)), p.DistanceSquared(new Segment3d(_c, _a)));\n                }\n                return p.DistanceSquared(new Segment3d(_b, _c));\n            }\n            if (new Vector3d(_c, _a).Cross(new Vector3d(_c, projection_point)).Dot(this._normal) < 0)\n            {\n                return p.DistanceSquared(new Segment3d(_c, _a));\n            }\n\n            // Projection point is inside\n            return p.DistanceSquared(projection_point);\n        }\n\n        /// <summary>\n        /// Calculates the point on the triangle closest to given point.\n        /// </summary>\n        public Point3d ClosestPoint(Point3d p)\n        {\n            this.DistanceTo(p, out Point3d closest_point);\n            return closest_point;\n        }\n\n        /// <summary>\n        /// Shortest distance between triangle and circle (including interior points)\n        /// </summary>\n        public double DistanceTo(Circle3d c)\n        {\n            Point3d point_on_circle, point_on_triangle;\n            return c.DistanceTo(this, out point_on_circle, out point_on_triangle);\n        }\n\n        /// <summary>\n        /// Shortest distance between triangle and circle (including interior points)\n        /// </summary>\n        /// <param name=\"c\">Target circle</param>\n        /// <param name=\"point_on_triangle\">Closest point on triangle</param>\n        /// <param name=\"point_on_circle\">Closest point on circle</param>\n        public double DistanceTo(Circle3d c, out Point3d point_on_triangle, out Point3d point_on_circle)\n        {\n            return c.DistanceTo(this, out point_on_circle, out point_on_triangle);\n        }\n\n        /// <summary>\n        /// Distance from triangle to polyhedron\n        /// </summary>\n        /// <param name=\"c\">Target polyhedron</param>\n        /// <param name=\"point_on_triangle\">Closest point on triangle</param>\n        /// <param name=\"point_on_polyhedron\">Closest point on polyhedron</param>\n        public double DistanceTo(ConvexPolyhedron c, out Point3d point_on_triangle, out Point3d point_on_polyhedron)\n        {\n            return c.DistanceTo(this, out point_on_polyhedron, out point_on_triangle);\n        }\n\n        /// <summary>\n        /// Distance from triangle to polyhedron\n        /// </summary>\n        public double DistanceTo(ConvexPolyhedron c)\n        {\n            return c.DistanceTo(this, out Point3d p1, out Point3d p2);\n        }\n\n        /// <summary>\n        /// Distance between triangle and segment\n        /// </summary>\n        public double DistanceTo(Segment3d s)\n        {\n            if (s.IsNotParallelTo(this.Plane))\n            {\n                //Segment is not parallel with triangle's plane, therefore possible intersection is point\n                object obj = s.IntersectionWith(this.Plane);\n                if (obj != null && object.ReferenceEquals(obj.GetType(), typeof(Point3d)))\n                {\n                    Point3d intersection_point = (Point3d)obj;\n                    // Check if intersection point is outside\n                    if (new Vector3d(_a, _b).Cross(new Vector3d(_a, intersection_point)).Dot(this._normal) < 0) goto Outside;\n                    if (new Vector3d(_b, _c).Cross(new Vector3d(_b, intersection_point)).Dot(this._normal) < 0) goto Outside;\n                    if (new Vector3d(_c, _a).Cross(new Vector3d(_c, intersection_point)).Dot(this._normal) < 0) goto Outside;\n                    return 0;\n                }\n            }\n\n            Outside:\n            double dist = s.P1.DistanceTo(this);\n            double dist2 = s.P2.DistanceTo(this);\n            if (dist2 < dist) dist = dist2;\n\n            dist2 = s.DistanceTo(new Segment3d(_a, _b));\n            if (dist2 < dist) dist = dist2;\n            dist2 = s.DistanceTo(new Segment3d(_b, _c));\n            if (dist2 < dist) dist = dist2;\n            dist2 = s.DistanceTo(new Segment3d(_c, _a));\n            if (dist2 < dist) dist = dist2;\n\n            return dist;\n        }\n\n        /// <summary>\n        /// Shortest distance between triangle and segment (with closest points)\n        /// </summary>\n        public double DistanceTo(Segment3d s, out Point3d point_on_triangle, out Point3d point_on_segment)\n        {\n            if (s.IsNotParallelTo(this.Plane))\n            {\n                //Segment is not parallel with triangle's plane, therefore possible intersection is point\n                object obj = s.IntersectionWith(this.Plane);\n                if (obj != null && object.ReferenceEquals(obj.GetType(), typeof(Point3d)))\n                {\n                    Point3d intersection_point = (Point3d)obj;\n                    // Check if intersection point is outside\n                    if (new Vector3d(_a, _b).Cross(new Vector3d(_a, intersection_point)).Dot(this._normal) < 0) goto Outside;\n                    if (new Vector3d(_b, _c).Cross(new Vector3d(_b, intersection_point)).Dot(this._normal) < 0) goto Outside;\n                    if (new Vector3d(_c, _a).Cross(new Vector3d(_c, intersection_point)).Dot(this._normal) < 0) goto Outside;\n                    point_on_triangle = intersection_point;\n                    point_on_segment = intersection_point;\n                    return 0;\n                }\n            }\n\n        Outside:\n            point_on_segment = s.P1;\n            double dist = s.P1.DistanceTo(this, out point_on_triangle);\n            double dist2 = s.P2.DistanceTo(this, out Point3d tpoint);\n            if (dist2 < dist)\n            {\n                point_on_segment = s.P2;\n                point_on_triangle = tpoint;\n                dist = dist2;\n            }\n                \n            dist2 = s.DistanceTo(new Segment3d(_a, _b), out Point3d spoint, out tpoint);\n            if (dist2 < dist)\n            {\n                point_on_segment = spoint;\n                point_on_triangle = tpoint;\n                dist = dist2;\n            }\n            dist2 = s.DistanceTo(new Segment3d(_b, _c), out spoint, out tpoint);\n            if (dist2 < dist)\n            {\n                point_on_segment = spoint;\n                point_on_triangle = tpoint;\n                dist = dist2;\n            }\n            dist2 = s.DistanceTo(new Segment3d(_c, _a), out spoint, out tpoint);\n            if (dist2 < dist)\n            {\n                point_on_segment = spoint;\n                point_on_triangle = tpoint;\n                dist = dist2;\n            }\n\n            return dist;\n        }\n\n        /// <summary>\n        /// Shortest distance between two triangles\n        /// </summary>\n        public double DistanceTo(Triangle t)\n        {\n\n            double dist = _DistanceToTriangle(t);\n\n            return dist;\n        }\n\n        /// <summary>\n        /// Shortest distance between two triangles (with closest points)\n        /// </summary>\n        public double DistanceTo(Triangle t, out Point3d point_on_this_triangle, out Point3d point_on_target_triangle)\n        {\n\n            double dist = _DistanceToTriangle(t, out point_on_this_triangle, out point_on_target_triangle);\n\n            return dist;\n        }\n\n        /// <summary>\n        /// Shortest distance between two triangles\n        /// </summary>\n        internal double _DistanceToTriangle(Triangle t)\n        {\n            double dist = double.PositiveInfinity;\n            double tmp;\n\n            tmp = t.DistanceTo(new Segment3d(this._a, this._b));\n            if (tmp <= GeometRi3D.Tolerance)\n            {\n                return tmp;\n            }\n            else if (tmp < dist)\n            {\n                dist = tmp;\n            }\n            tmp = t.DistanceTo(new Segment3d(this._a, this._c));\n            if (tmp <= GeometRi3D.Tolerance)\n            {\n                return tmp;\n            }\n            else if (tmp < dist)\n            {\n                dist = tmp;\n            }\n            tmp = t.DistanceTo(new Segment3d(this._b, this._c));\n            if (tmp <= GeometRi3D.Tolerance)\n            {\n                return tmp;\n            }\n            else if (tmp < dist)\n            {\n                dist = tmp;\n            }\n            tmp = this.DistanceTo(new Segment3d(t._a, t._b));\n            if (tmp <= GeometRi3D.Tolerance)\n            {\n                return tmp;\n            }\n            else if (tmp < dist)\n            {\n                dist = tmp;\n            }\n            tmp = this.DistanceTo(new Segment3d(t._a, t._c));\n            if (tmp <= GeometRi3D.Tolerance)\n            {\n                return tmp;\n            }\n            else if (tmp < dist)\n            {\n                dist = tmp;\n            }\n            tmp = this.DistanceTo(new Segment3d(t._b, t._c));\n            if (tmp <= GeometRi3D.Tolerance)\n            {\n                return tmp;\n            }\n            else if (tmp < dist)\n            {\n                dist = tmp;\n            }\n\n            return dist;\n        }\n\n        /// <summary>\n        /// Shortest distance between two triangles (with closest points)\n        /// </summary>\n        internal double _DistanceToTriangle(Triangle t, out Point3d point_on_this_triangle, out Point3d point_on_target_triangle)\n        {\n            double dist = double.PositiveInfinity;\n            double tmp;\n            Point3d point_on_triangle, point_on_segment;\n\n            tmp = t.DistanceTo(new Segment3d(this._a, this._b), out point_on_triangle, out point_on_segment);\n            point_on_this_triangle = point_on_segment;\n            point_on_target_triangle = point_on_triangle;\n            if (tmp <= GeometRi3D.Tolerance)\n            {\n                return tmp;\n            }\n            else if (tmp < dist)\n            {\n                dist = tmp;\n            }\n            tmp = t.DistanceTo(new Segment3d(this._a, this._c), out point_on_triangle, out point_on_segment);\n            if (tmp <= GeometRi3D.Tolerance)\n            {\n                point_on_this_triangle = point_on_segment;\n                point_on_target_triangle = point_on_triangle;\n                return tmp;\n            }\n            else if (tmp < dist)\n            {\n                point_on_this_triangle = point_on_segment;\n                point_on_target_triangle = point_on_triangle;\n                dist = tmp;\n            }\n            tmp = t.DistanceTo(new Segment3d(this._b, this._c), out point_on_triangle, out point_on_segment);\n            if (tmp <= GeometRi3D.Tolerance)\n            {\n                point_on_this_triangle = point_on_segment;\n                point_on_target_triangle = point_on_triangle;\n                return tmp;\n            }\n            else if (tmp < dist)\n            {\n                point_on_this_triangle = point_on_segment;\n                point_on_target_triangle = point_on_triangle;\n                dist = tmp;\n            }\n            tmp = this.DistanceTo(new Segment3d(t._a, t._b), out point_on_triangle, out point_on_segment);\n            if (tmp <= GeometRi3D.Tolerance)\n            {\n                point_on_this_triangle = point_on_triangle;\n                point_on_target_triangle = point_on_segment;\n                return tmp;\n            }\n            else if (tmp < dist)\n            {\n                point_on_this_triangle = point_on_triangle;\n                point_on_target_triangle = point_on_segment;\n                dist = tmp;\n            }\n            tmp = this.DistanceTo(new Segment3d(t._a, t._c), out point_on_triangle, out point_on_segment);\n            if (tmp <= GeometRi3D.Tolerance)\n            {\n                point_on_this_triangle = point_on_triangle;\n                point_on_target_triangle = point_on_segment;\n                return tmp;\n            }\n            else if (tmp < dist)\n            {\n                point_on_this_triangle = point_on_triangle;\n                point_on_target_triangle = point_on_segment;\n                dist = tmp;\n            }\n            tmp = this.DistanceTo(new Segment3d(t._b, t._c), out point_on_triangle, out point_on_segment);\n            if (tmp <= GeometRi3D.Tolerance)\n            {\n                point_on_this_triangle = point_on_triangle;\n                point_on_target_triangle = point_on_segment;\n                return tmp;\n            }\n            else if (tmp < dist)\n            {\n                point_on_this_triangle = point_on_triangle;\n                point_on_target_triangle = point_on_segment;\n                dist = tmp;\n            }\n\n            return dist;\n        }\n        #endregion\n\n        /// <summary>\n        /// Orthogonal projection of the triangle to line\n        /// </summary>\n        public Segment3d ProjectionTo(Line3d l)\n        {\n            double d12, d23, d13;\n            Point3d p1, p2, p3;\n            p1 = _a.ProjectionTo(l);\n            p2 = _b.ProjectionTo(l);\n            p3 = _c.ProjectionTo(l);\n            d12 = p1.DistanceTo(p2);\n            d13 = p1.DistanceTo(p3);\n            d23 = p2.DistanceTo(p3);\n            if (d12 >= d13 && d12 >= d23)\n            {\n                return new Segment3d(p1, p2);\n            }\n            else if (d13 >= d23)\n            {\n                return new Segment3d(p1, p3);\n            }\n            else\n            {\n                return new Segment3d(p2, p3);\n            }\n        }\n\n        /// <summary>\n        /// Get intersection of line with triangle.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'.\n        /// </summary>\n        public object IntersectionWith(Line3d l)\n        {\n\n            // Relative tolerance ================================\n            if (!GeometRi3D.UseAbsoluteTolerance)\n            {\n                double tol = GeometRi3D.Tolerance;\n                GeometRi3D.Tolerance = tol * Max(AB, Max(BC, AC));\n                GeometRi3D.UseAbsoluteTolerance = true;\n                object result = this.IntersectionWith(l);\n                GeometRi3D.UseAbsoluteTolerance = false;\n                GeometRi3D.Tolerance = tol;\n                return result;\n            }\n            //====================================================\n\n            Plane3d s = new Plane3d(this.A, this.Normal);\n\n            object obj = l.IntersectionWith(s);\n            if (obj == null)\n            {\n                return null;\n            }\n            else\n            {\n                if (obj.GetType() == typeof(Line3d))\n                {\n                    // Coplanar line and triangle\n                    return _coplanar_IntersectionWith(l);\n                }\n                else\n                {\n                    // result of intersection is point\n                    Point3d p = (Point3d)obj;\n                    if (p.BelongsTo(this))\n                    {\n                        return p;\n                    }\n                    else\n                    {\n                        return null;\n                    }\n                }\n            }\n\n        }\n\n        /// <summary>\n        /// Get intersection of plane with triangle.\n        /// Returns 'null' (no intersection) or object of type 'Triangle', 'Point3d' or 'Segment3d'.\n        /// </summary>\n        public object IntersectionWith(Plane3d s)\n        {\n\n            // Relative tolerance ================================\n            if (!GeometRi3D.UseAbsoluteTolerance)\n            {\n                double tol = GeometRi3D.Tolerance;\n                GeometRi3D.Tolerance = tol * Max(AB, Max(BC, AC));\n                GeometRi3D.UseAbsoluteTolerance = true;\n                object result = this.IntersectionWith(s);\n                GeometRi3D.UseAbsoluteTolerance = false;\n                GeometRi3D.Tolerance = tol;\n                return result;\n            }\n            //====================================================\n\n            Plane3d st = new Plane3d(this.A, this.Normal);\n\n            if (s.IsParallelTo(st))\n            {\n                if (A.BelongsTo(s))\n                {\n                    return this.Copy();\n                }\n                else\n                {\n                    return null;\n                }\n            }\n\n            Line3d l = (Line3d)s.IntersectionWith(st);\n\n            // Line \"l\" is coplanar with triangle by construction\n\n            return _coplanar_IntersectionWith(l);\n        }\n\n        /// <summary>\n        /// Get intersection of line with triangle (coplanar).\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'.\n        /// </summary>\n        internal object _coplanar_IntersectionWith(Line3d l)\n        {\n            Point3d onAB, onBC, onAC;\n            double pos_onAB, pos_onBC, pos_onAC;\n\n            // Check intersection with first two sides\n            onAB = l.PerpendicularTo(new Segment3d(_a, _b).Line);\n            onBC = l.PerpendicularTo(new Segment3d(_b, _c).Line);\n            if (onAB != null && onBC != null)\n            {\n                pos_onAB = new Vector3d(_a, onAB).Dot(new Vector3d(_a, _b)) / (AB * AB);\n                pos_onBC = new Vector3d(_b, onBC).Dot(new Vector3d(_b, _c)) / (BC * BC);\n                if (pos_onAB >= 1 - GeometRi3D.Tolerance && pos_onAB <= 1 + GeometRi3D.Tolerance &&\n                    pos_onBC >= -GeometRi3D.Tolerance && pos_onBC <= GeometRi3D.Tolerance)\n                {\n                    // Check intersection with AC\n                    onAC = l.PerpendicularTo(new Segment3d(_a, _c).Line);\n                    if (onAC != null)\n                    {\n                        pos_onAC = new Vector3d(_a, onAC).Dot(new Vector3d(_a, _c)) / (AC * AC);\n                        if (pos_onAC > -GeometRi3D.Tolerance && pos_onAC <= 1 + GeometRi3D.Tolerance)\n                        {\n                            return new Segment3d(B, onAC);\n                        }\n                    }\n\n                    // intersection in one point \"B\"\n                    return B;\n                }\n                else if (pos_onAB >= -GeometRi3D.Tolerance && pos_onAB < 1 - GeometRi3D.Tolerance &&\n                         pos_onBC > GeometRi3D.Tolerance && pos_onBC <= 1 + GeometRi3D.Tolerance)\n                {\n                    return new Segment3d(onAB, onBC);\n                }\n            }\n\n            //Check intersection with third side\n            onAC = l.PerpendicularTo(new Segment3d(_a, _c).Line);\n            if (onAB != null && onAC != null)\n            {\n                pos_onAB = new Vector3d(_a, onAB).Dot(new Vector3d(_a, _b)) / (AB * AB);\n                pos_onAC = new Vector3d(_a, onAC).Dot(new Vector3d(_a, _c)) / (AC * AC);\n                if (pos_onAB >= -GeometRi3D.Tolerance && pos_onAB <= GeometRi3D.Tolerance &&\n                    pos_onAC >= -GeometRi3D.Tolerance && pos_onAC <= GeometRi3D.Tolerance)\n                {\n                    // Check intersection with BC\n                    onBC = l.PerpendicularTo(new Segment3d(_b, _c).Line);\n                    if (onBC != null)\n                    {\n                        pos_onBC = new Vector3d(_b, onBC).Dot(new Vector3d(_b, _c)) / (BC * BC);\n                        if (pos_onBC > -GeometRi3D.Tolerance && pos_onAC <= 1 + GeometRi3D.Tolerance)\n                        {\n                            return new Segment3d(A, onBC);\n                        }\n                    }\n                    // intersection in one point \"A\"\n                    return A;\n                }\n                else if (pos_onAB > GeometRi3D.Tolerance && pos_onAB <= 1 + GeometRi3D.Tolerance &&\n                         pos_onAC > GeometRi3D.Tolerance && pos_onAC <= 1 + GeometRi3D.Tolerance)\n                {\n                    return new Segment3d(onAB, onAC);\n                }\n            }\n\n            if (onBC != null && onAC != null)\n            {\n                pos_onBC = new Vector3d(_b, onBC).Dot(new Vector3d(_b, _c)) / (BC * BC);\n                pos_onAC = new Vector3d(_a, onAC).Dot(new Vector3d(_a, _c)) / (AC * AC);\n                if (pos_onBC >= 1 - GeometRi3D.Tolerance && pos_onBC <= 1 + GeometRi3D.Tolerance &&\n                    pos_onAC >= 1 - GeometRi3D.Tolerance && pos_onAC <= 1 + GeometRi3D.Tolerance)\n                {\n                    // Check intersection with AB\n                    if (onAB != null)\n                    {\n                        pos_onAB = new Vector3d(_a, onAB).Dot(new Vector3d(_a, _b)) / (AB * AB);\n                        if (pos_onAB > -GeometRi3D.Tolerance && pos_onAC <= 1 + GeometRi3D.Tolerance)\n                        {\n                            return new Segment3d(C, onAB);\n                        }\n                    }\n                    // intersection in one point \"C\"\n                    return C;\n                }\n                else if (pos_onBC >= -GeometRi3D.Tolerance && pos_onBC < 1 - GeometRi3D.Tolerance &&\n                         pos_onAC >= -GeometRi3D.Tolerance && pos_onAC < 1 - GeometRi3D.Tolerance)\n                {\n                    return new Segment3d(onBC, onAC);\n                }\n            }\n\n            return null;\n        }\n\n\n        /// <summary>\n        /// Get intersection of segment with triangle.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'.\n        /// </summary>\n        public object IntersectionWith(Segment3d s)\n        {\n\n            // Relative tolerance ================================\n            if (!GeometRi3D.UseAbsoluteTolerance)\n            {\n                double tol = GeometRi3D.Tolerance;\n                GeometRi3D.Tolerance = tol * Max(s.Length, Max(AB, Max(BC, AC)));\n                GeometRi3D.UseAbsoluteTolerance = true;\n                object result = this.IntersectionWith(s);\n                GeometRi3D.UseAbsoluteTolerance = false;\n                GeometRi3D.Tolerance = tol;\n                return result;\n            }\n            //====================================================\n\n            object obj = this.IntersectionWith(s.Line);\n\n            if (obj == null)\n            {\n                return null;\n            }\n            else if (obj.GetType() == typeof(Point3d))\n            {\n                Point3d p = (Point3d)obj;\n                if (p.BelongsTo(s))\n                {\n                    return p;\n                }\n                else\n                {\n                    return null;\n                }\n            }\n            else\n            {\n                return s.IntersectionWith((Segment3d)obj);\n            }\n        }\n\n        /// <summary>\n        /// Get intersection of ray with triangle.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'.\n        /// </summary>\n        public object IntersectionWith(Ray3d r)\n        {\n            // Relative tolerance ================================\n            if (!GeometRi3D.UseAbsoluteTolerance)\n            {\n                double tol = GeometRi3D.Tolerance;\n                GeometRi3D.Tolerance = tol * Max(AB, Max(BC, AC));\n                GeometRi3D.UseAbsoluteTolerance = true;\n                object result = this.IntersectionWith_Moller(r);\n                GeometRi3D.UseAbsoluteTolerance = false;\n                GeometRi3D.Tolerance = tol;\n                return result;\n            }\n            //====================================================\n            else\n            {\n                return IntersectionWith_Moller(r);\n            }\n        }\n\n        [Obsolete(\"this method is not optimzed. For better performance use IntersectionWith_Moller() method instead.\")]\n        /// <summary>\n        /// Get intersection of ray with triangle.\n        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'.\n        /// </summary>\n        private object IntersectionWith_original(Ray3d r)\n        {\n            object obj = this.IntersectionWith(r.ToLine);\n\n            if (obj == null)\n            {\n                return null;\n            }\n            else if (obj.GetType() == typeof(Point3d))\n            {\n                Point3d p = (Point3d)obj;\n                if (p.BelongsTo(r))\n                {\n                    return p;\n                }\n                else\n                {\n                    return null;\n                }\n            }\n            else\n            {\n                return r.IntersectionWith((Segment3d)obj);\n            }\n        }\n\n\n        /// <summary>\n        /// acc. to https://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm\n        /// </summary>\n        /// <param name=\"ray\"></param>\n        /// <returns></returns>\n        private object IntersectionWith_Moller(Ray3d ray)\n        {\n            double tolerance = GeometRi3D.Tolerance;\n\n            Point3d vertex0 = A;\n            Point3d vertex1 = B;\n            Point3d vertex2 = C;\n\n            Vector3d edge1 = new Vector3d(vertex0, vertex1);\n            Vector3d edge2 = new Vector3d(vertex0, vertex2);\n            Vector3d h = ray.Direction.Cross(edge2);\n            double a = edge1.Dot(h);\n\n            if (a > -tolerance && a < tolerance)\n            {\n                // The ray is parallel to the triangle\n                // Check if the ray is in the plane of the triangle\n                Plane3d plane = ToPlane;\n                if (Math.Abs(plane.Normal.Dot(ray.Direction)) < tolerance && ray.Point.BelongsTo(plane))\n                {\n                    // Ray in the plane of the triangle: intersection = segment (portion of the ray inside the triangle)\n                    // We look for the intersections of the ray with the 3 edges of the triangle\n                    Point3d[] intersections = new Point3d[2];\n                    int count = 0;\n                    Segment3d[] edges = new Segment3d[] {\n                        new Segment3d(vertex0, vertex1),\n                        new Segment3d(vertex1, vertex2),\n                        new Segment3d(vertex2, vertex0)\n                    };\n                    foreach (var edge in edges)\n                    {\n                        object inter = ray.IntersectionWith(edge);\n                        if (inter is Point3d p && count < 2)\n                        {\n                            // Check that the point is actually inside the triangle\n                            if (p.BelongsTo(this))\n                                intersections[count++] = p;\n                        }\n                    }\n                    if (count == 2 && intersections[0] != intersections[1])\n                    {\n                        return new Segment3d(intersections[0], intersections[1]);\n                    }\n                    else if (count == 1)\n                    {\n                        if (intersections[0] == ray.Point)\n                            return intersections[0];\n                        else\n                            return new Segment3d(ray.Point, intersections[0]);\n                    }\n                    else\n                    {\n                        return null;\n                    }\n                }\n                else\n                {\n                    return null;\n                }\n            }\n\n            double f = 1.0 / a;\n            Vector3d s = new Vector3d(vertex0, ray.Point);\n            double u = f * s.Dot(h);\n            if (u < 0.0 - tolerance || u > 1.0 + tolerance)\n            {\n                return null;\n            }\n\n            Vector3d q = s.Cross(edge1);\n            double v = f * ray.Direction.Dot(q);\n            if (v < 0.0 && Math.Abs(v) > tolerance || u + v > 1.0 && Math.Abs(u + v - 1) > tolerance)\n            {\n                return null;\n            }\n\n            double t = f * edge2.Dot(q);\n            if (t > tolerance)\n            {\n                // intersectionPoint = rayOrigin + t * rayVector\n                Point3d intersectionPoint = ray.Point + ray.Direction.Mult(t);\n                return intersectionPoint;\n            }\n            else\n            {\n                return null;\n            }\n        }\n\n        /// <summary>\n        /// Intersection check between circle and triangle\n        /// </summary>\n        public bool Intersects(Circle3d c)\n        {\n            return c.Intersects(this);\n        }\n\n        /// <summary>\n        /// Intersection check between tetrahedron and triangle\n        /// </summary>\n        public bool Intersects(Tetrahedron t)\n        {\n            return t.Intersects(this);\n        }\n\n        /// <summary>\n        /// Intersection check between polyhedron and triangle.\n        /// Behaviour for touching objects is undefined.\n        /// </summary>\n        public bool Intersects(ConvexPolyhedron c)\n        {\n            return c.Intersects(this);\n        }\n\n        /// <summary>\n        /// Intersection check between triangle and sphere\n        /// </summary>\n        public bool Intersects(Sphere s)\n        {\n            Point3d projection_point = s.Center.ProjectionTo(Plane);\n\n            if (s.Center.DistanceTo(projection_point) > s.R)\n            {\n                return false;\n            }\n            else\n            {\n                if (projection_point.BelongsTo(this)) return true;\n\n                if (s.IntersectionWith(new Segment3d(A, B)) != null) return true;\n                if (s.IntersectionWith(new Segment3d(A, C)) != null) return true;\n                if (s.IntersectionWith(new Segment3d(C, B)) != null) return true;\n            }\n            return false;\n        }\n\n        /// <summary>\n        /// Intersection check between two triangles\n        /// </summary>\n        public bool Intersects(Triangle t)\n        {\n            if (this.IsCoplanarTo(t))\n            {\n                if (t._a.BelongsTo(this)) return true;\n                if (t._b.BelongsTo(this)) return true;\n                if (t._c.BelongsTo(this)) return true;\n\n                if (this._a.BelongsTo(t)) return true;\n                if (this._b.BelongsTo(t)) return true;\n                if (this._c.BelongsTo(t)) return true;\n\n                if (this.IntersectionWith(new Segment3d(t._a, t._b)) != null) return true;\n                if (this.IntersectionWith(new Segment3d(t._b, t._c)) != null) return true;\n                if (this.IntersectionWith(new Segment3d(t._c, t._a)) != null) return true;\n            }\n\n            object obj = this.IntersectionWith(t.Plane);\n            if (obj != null && obj.GetType() == typeof(Point3d))\n            {\n                return ((Point3d)obj).BelongsTo(t);\n            }\n            else if (obj != null && obj.GetType() == typeof(Segment3d))\n            {\n                return ((Segment3d)obj).IntersectionWith(t) != null;\n            }\n\n            return false;\n        }\n\n        /// <summary>\n        /// Check intersection of triangle with box\n        /// </summary>\n        public bool Intersects(Box3d box)\n        {\n            return box.Intersects(this);\n        }\n\n        internal override int _PointLocation(Point3d p)\n        {\n\n            if (GeometRi3D.UseAbsoluteTolerance)\n            {\n                Point3d proj = p.ProjectionTo(this.Plane);\n                if (GeometRi3D.AlmostEqual(p.DistanceTo(proj), 0))\n                {\n                    return _InPlanePointLocation(proj);\n                }\n                else\n                {\n                    return -1; // Point is outside\n                }\n            }\n            else\n            {\n                double tol = GeometRi3D.Tolerance;\n                GeometRi3D.Tolerance = tol * (AB + BC + AC) / 3;\n                GeometRi3D.UseAbsoluteTolerance = true;\n                int result = this._PointLocation(p);\n                GeometRi3D.UseAbsoluteTolerance = false;\n                GeometRi3D.Tolerance = tol;\n                return result;\n            }\n        }\n\n        internal int _InPlanePointLocation(Point3d p)\n        {\n            // Point \"p\" should be located on triangles' plane !!!\n            if (GeometRi3D.UseAbsoluteTolerance)\n            {\n                if (p.BelongsTo(new Segment3d(_a, _b)) || p.BelongsTo(new Segment3d(_a, _c)) || p.BelongsTo(new Segment3d(_c, _b)))\n                {\n                    return 0; // Point is on boundary\n                }\n                else\n                {\n\n                    double area = this.Area;\n\n                    double alpha = new Vector3d(p, _b).Cross(new Vector3d(p, _c)).Norm / (2 * area);\n                    double beta = new Vector3d(p, _c).Cross(new Vector3d(p, _a)).Norm / (2 * area);\n                    double gamma = new Vector3d(p, _a).Cross(new Vector3d(p, _b)).Norm / (2 * area);\n\n                    if (GeometRi3D.AlmostEqual(((alpha + beta + gamma) - 1.0) * (AB + BC + AC) / 3, 0.0))\n                    {\n                        return 1; // Point is strictly inside\n                    }\n                    else\n                    {\n                        return -1;\n                    }\n                }\n            }\n            else\n            {\n                double tol = GeometRi3D.Tolerance;\n                GeometRi3D.Tolerance = tol * (AB + BC + AC) / 3;\n                GeometRi3D.UseAbsoluteTolerance = true;\n                int result = this._InPlanePointLocation(p);\n                GeometRi3D.UseAbsoluteTolerance = false;\n                GeometRi3D.Tolerance = tol;\n                return result;\n            }\n        }\n\n        #region \"AngleTo\"\n        /// <summary>\n        /// Angle between two objects in radians (0 &lt; angle &lt; Pi)\n        /// </summary>\n        public double AngleTo(ILinearObject obj)\n        {\n            return GeometRi3D.GetAngle(this, obj);\n        }\n        /// <summary>\n        /// Angle between two objects in degrees (0 &lt; angle &lt; 180)\n        /// </summary>\n        public double AngleToDeg(ILinearObject obj)\n        {\n            return AngleTo(obj) * 180 / PI;\n        }\n\n        /// <summary>\n        /// Angle between two objects in radians (0 &lt; angle &lt; Pi)\n        /// </summary>\n        public double AngleTo(IPlanarObject obj)\n        {\n            return GeometRi3D.GetAngle(this, obj);\n        }\n        /// <summary>\n        /// Angle between two objects in degrees (0 &lt; angle &lt; 180)\n        /// </summary>\n        public double AngleToDeg(IPlanarObject obj)\n        {\n            return AngleTo(obj) * 180 / PI;\n        }\n        #endregion\n\n        #region \"TranslateRotateReflect\"\n        /// <summary>\n        /// Translate triangle by a vector\n        /// </summary>\n        public Triangle Translate(Vector3d v)\n        {\n            return new Triangle(_a.Translate(v), _b.Translate(v), _c.Translate(v));\n        }\n\n        /// <summary>\n        /// Rotate triangle by a given rotation matrix\n        /// </summary>\n        [System.Obsolete(\"use Rotation object and specify rotation center: this.Rotate(Rotation r, Point3d p)\")]\n        public Triangle Rotate(Matrix3d m)\n        {\n            return new Triangle(_a.Rotate(m), _b.Rotate(m), _c.Rotate(m));\n        }\n\n        /// <summary>\n        /// Rotate triangle by a given rotation matrix around point 'p' as a rotation center\n        /// </summary>\n        [System.Obsolete(\"use Rotation object: this.Rotate(Rotation r, Point3d p)\")]\n        public Triangle Rotate(Matrix3d m, Point3d p)\n        {\n            return new Triangle(_a.Rotate(m, p), _b.Rotate(m, p), _c.Rotate(m, p));\n        }\n\n        /// <summary>\n        /// Rotate triangle around point 'p' as a rotation center\n        /// </summary>\n        public Triangle Rotate(Rotation r, Point3d p)\n        {\n            return new Triangle(_a.Rotate(r, p), _b.Rotate(r, p), _c.Rotate(r, p));\n        }\n\n        /// <summary>\n        /// Reflect triangle in given point\n        /// </summary>\n        public Triangle ReflectIn(Point3d p)\n        {\n            return new Triangle(_a.ReflectIn(p), _b.ReflectIn(p), _c.ReflectIn(p));\n        }\n\n        /// <summary>\n        /// Reflect triangle in given line\n        /// </summary>\n        public Triangle ReflectIn(Line3d l)\n        {\n            return new Triangle(_a.ReflectIn(l), _b.ReflectIn(l), _c.ReflectIn(l));\n        }\n\n        /// <summary>\n        /// Reflect triangle in given plane\n        /// </summary>\n        public Triangle ReflectIn(Plane3d s)\n        {\n            return new Triangle(_a.ReflectIn(s), _b.ReflectIn(s), _c.ReflectIn(s));\n        }\n\n        /// <summary>\n        /// Scale triangle relative to given point\n        /// </summary>\n        public virtual Triangle Scale(double scale, Point3d scaling_center)\n        {\n            Point3d p1 = scaling_center + scale * (_a - scaling_center);\n            Point3d p2 = scaling_center + scale * (_b - scaling_center);\n            Point3d p3 = scaling_center + scale * (_c - scaling_center);\n            return new Triangle(p1, p2, p3);\n        }\n        #endregion\n\n        /// <summary>\n        /// Determines whether two objects are equal.\n        /// </summary>\n        public override bool Equals(object obj)\n        {\n            if (obj == null || (!object.ReferenceEquals(this.GetType(), obj.GetType())))\n            {\n                return false;\n            }\n            Triangle t = (Triangle)obj;\n            if (GeometRi3D.UseAbsoluteTolerance)\n            {\n                return ((this.A == t.A || this.A == t.B || this.A == t.C) &&\n                        (this.B == t.A || this.B == t.B || this.B == t.C) &&\n                        (this.C == t.A || this.C == t.B || this.C == t.C));\n            }\n            else\n            {\n                double tol = GeometRi3D.Tolerance;\n                GeometRi3D.Tolerance = tol * this.Perimeter;\n                GeometRi3D.UseAbsoluteTolerance = true;\n                bool result = ((this.A == t.A || this.A == t.B || this.A == t.C) &&\n                               (this.B == t.A || this.B == t.B || this.B == t.C) &&\n                               (this.C == t.A || this.C == t.B || this.C == t.C));\n                GeometRi3D.UseAbsoluteTolerance = false;\n                GeometRi3D.Tolerance = tol;\n                return result;\n            }\n\n        }\n\n        /// <summary>\n        /// Returns the hashcode for the object.\n        /// </summary>\n        public override int GetHashCode()\n        {\n            return GeometRi3D.HashFunction(_a.GetHashCode(), _b.GetHashCode(), _c.GetHashCode());\n        }\n\n        /// <summary>\n        /// String representation of an object in global coordinate system.\n        /// </summary>\n        public override String ToString()\n        {\n            return ToString(Coord3d.GlobalCS);\n        }\n\n        /// <summary>\n        /// String representation of an object in reference coordinate system.\n        /// </summary>\n        public String ToString(Coord3d coord)\n        {\n            System.Text.StringBuilder str = new System.Text.StringBuilder();\n            string nl = System.Environment.NewLine;\n\n            if (coord == null) { coord = Coord3d.GlobalCS; }\n            Point3d A = _a.ConvertTo(coord);\n            Point3d B = _b.ConvertTo(coord);\n            Point3d C = _c.ConvertTo(coord);\n\n            str.Append(\"Triangle:\" + nl);\n            str.Append(string.Format(\"A -> ({0,10:g5}, {1,10:g5}, {2,10:g5})\", A.X, A.Y, A.Z) + nl);\n            str.Append(string.Format(\"B -> ({0,10:g5}, {1,10:g5}, {2,10:g5})\", B.X, B.Y, B.Z) + nl);\n            str.Append(string.Format(\"C -> ({0,10:g5}, {1,10:g5}, {2,10:g5})\", C.X, C.Y, C.Z));\n            return str.ToString();\n        }\n\n        // Operators overloads\n        //-----------------------------------------------------------------\n\n        public static bool operator ==(Triangle t1, Triangle t2)\n        {\n            if (object.ReferenceEquals(t1, null))\n                return object.ReferenceEquals(t2, null);\n            return t1.Equals(t2);\n        }\n        public static bool operator !=(Triangle t1, Triangle t2)\n        {\n            if (object.ReferenceEquals(t1, null))\n                return !object.ReferenceEquals(t2, null);\n            return !t1.Equals(t2);\n        }\n   \n    }\n}\n\n"
  },
  {
    "path": "GeometRi/Vector3D.cs",
    "content": "﻿using System;\nusing static System.Math;\n\nnamespace GeometRi\n{\n    /// <summary>\n    /// Vector in 3D space defined in global or local reference frame.\n    /// </summary>\n#if NET20_OR_GREATER\n    [Serializable]\n#endif\n    public class Vector3d : ILinearObject\n    {\n\n        private double[] val;\n        internal Coord3d _coord;\n        private double? _norm;\n        private double? _squaredNorm;\n        private Vector3d _normalized;\n\n        internal bool HasChanged { get; private set; }\n       private void CheckFields()\n        {\n            if (HasChanged)\n            {\n                HasChanged = false;\n                ClearCache();\n            }\n        }\n        private void ClearCache()\n        {\n            _norm = null;\n            _squaredNorm = null;\n            _normalized = null;\n        }\n  \n\n\n        #region \"Constructors\"\n        /// <summary>\n        /// Default constructor, initializes zero vector.\n        /// </summary>\n        /// <param name=\"coord\">Reference coordinate system (default - Coord3d.GlobalCS).</param>\n        public Vector3d(Coord3d coord = null)\n        {\n            this.val = new double[3] { 0, 0, 0 };\n            _coord = (coord == null) ? Coord3d.GlobalCS : coord;\n        }\n\n        /// <summary>\n        /// Initializes vector object using components in reference coordinate system.\n        /// </summary>\n        /// <param name=\"coord\">Reference coordinate system (default - Coord3d.GlobalCS).</param>\n        public Vector3d(double X, double Y, double Z, Coord3d coord = null)\n        {\n            this.val = new double[3] { X, Y, Z };\n            _coord = (coord == null) ? Coord3d.GlobalCS : coord;\n        }\n\n        /// <summary>\n        /// Initializes vector object as radius vector of a point in reference coordinate system.\n        /// </summary>\n        public Vector3d(Point3d p, Coord3d coord = null)\n        {\n            _coord = (coord == null) ? Coord3d.GlobalCS : coord;\n            if (p.Coord == _coord)\n            {\n                this.val = new double[3] { p.X, p.Y, p.Z };\n            }\n            else\n            {\n\n            }\n            Point3d _p = p.ConvertTo(coord);\n            this.val = new double[3] { _p.X, _p.Y, _p.Z };\n        }\n\n        /// <summary>\n        /// Initializes vector object using two points in reference coordinate system of the first point.\n        /// </summary>\n        /// <param name=\"p1\">Start point.</param>\n        /// <param name=\"p2\">End point.</param>\n        public Vector3d(Point3d p1, Point3d p2)\n        {\n            if (p1.Coord != p2.Coord)\n                p2 = p2.ConvertTo(p1.Coord);\n            this.val = new double[3];\n            this.val[0] = p2.X - p1.X;\n            this.val[1] = p2.Y - p1.Y;\n            this.val[2] = p2.Z - p1.Z;\n            _coord = p1.Coord;\n        }\n\n        /// <summary>\n        /// Initializes vector using double array.\n        /// </summary>\n        /// <param name=\"coord\">Reference coordinate system (default - Coord3d.GlobalCS).</param>\n        public Vector3d(double[] a, Coord3d coord = null)\n        {\n            //if (a.GetUpperBound(0) < 2)\n            //    throw new Exception(\"Vector3d: Array size mismatch\");\n            this.val = new double[3];\n            this.val[0] = a[0];\n            this.val[1] = a[1];\n            this.val[2] = a[2];\n            _coord = (coord == null) ? Coord3d.GlobalCS : coord;\n        }\n        #endregion\n\n        /// <summary>\n        /// Uniformly distrbuted random vector of unit length\n        /// </summary>\n        public static Vector3d Random()\n        {\n            if (GeometRi3D.rnd == null)\n            {\n                GeometRi3D.rnd = new Random();\n            }\n            \n            double u = GeometRi3D.rnd.NextDouble();\n            double v = GeometRi3D.rnd.NextDouble();\n            double theta = Acos(2 * u - 1);\n            double phi = 2 * PI * v;\n\n            double x = Sin(theta) * Cos(phi);\n            double y = Sin(theta) * Sin(phi);\n            double z = Cos(theta);\n            return new Vector3d(x, y, z);\n        }\n\n        /// <summary>\n        /// Creates copy of the object\n        /// </summary>\n        public Vector3d Copy()\n        {\n            return new Vector3d(val, _coord);\n        }\n\n        public double this[int i]\n        {\n            get { return val[i]; }\n            set { val[i] = value; }\n        }\n\n        /// <summary>\n        /// X component in reference coordinate system\n        /// </summary>\n        public double X\n        {\n            get { return val[0]; }\n            set { val[0] = value; HasChanged = true; }\n        }\n\n        /// <summary>\n        /// Y component in reference coordinate system\n        /// </summary>\n        public double Y\n        {\n            get { return val[1]; }\n            set { val[1] = value;  HasChanged = true;}\n        }\n\n        /// <summary>\n        /// Z component in reference coordinate system\n        /// </summary>\n        public double Z\n        {\n            get { return val[2]; }\n            set { val[2] = value;  HasChanged = true;}\n        }\n\n        /// <summary>\n        /// Norm of a vector\n        /// </summary>\n        public double Norm\n        {\n            get\n            {\n                CheckFields();\n                if (_norm == null)\n                {\n                    _norm = Sqrt(val[0] * val[0] + val[1] * val[1] + val[2] * val[2]);\n                }\n                return _norm.Value;\n            }\n        }\n\n        public double NormSquared\n        {\n            get\n            {\n                CheckFields();\n                if (_squaredNorm == null)\n                {\n                    _squaredNorm = val[0] * val[0] + val[1] * val[1] + val[2] * val[2];\n                }\n                return _squaredNorm.Value;\n            }\n        }\n\n        /// <summary>\n        /// Minimal element of a vector\n        /// </summary>\n        public double MinElement\n        {\n            get { return Min(Min(val[0], val[1]), val[2]); }\n        }\n\n        /// <summary>\n        /// Maximal element of a vector\n        /// </summary>\n        public double MaxElement\n        {\n            get { return Max(Max(val[0], val[1]), val[2]); }\n        }\n\n        /// <summary>\n        ///  Reference coordinate system\n        /// </summary>\n        public Coord3d Coord\n        {\n            get { return _coord; }\n        }\n\n        // ILinearObject interface implementation\n        public Vector3d Direction\n        {\n            get { return this.Normalized;  }\n        }\n\n        public bool IsOriented\n        {\n            get {  return true;  }\n        }\n\n        /// <summary>\n        /// Returns line passing through origin in the direction of vector\n        /// </summary>\n        public Line3d ToLine\n        {\n            get { return new Line3d(new Point3d(), this.Direction); }\n        }\n        //////////////////////////////////////////\n\n        #region \"ParallelMethods\"\n        /// <summary>\n        /// Check if two objects are parallel\n        /// </summary>\n        public bool IsParallelTo(ILinearObject obj)\n        {\n            Vector3d v = obj.Direction;\n            if ((this._coord != v._coord))\n                v = v.ConvertTo(this._coord);\n\n            return GeometRi3D.AlmostEqual(Math.Abs(this.Normalized.Dot(v.Normalized)), 1.0);        \n        }\n\n        /// <summary>\n        /// Check if two objects are NOT parallel\n        /// </summary>\n        public bool IsNotParallelTo(ILinearObject obj)\n        {\n            return ! this.IsParallelTo(obj);\n        }\n\n        /// <summary>\n        /// Check if two objects are orthogonal\n        /// </summary>\n        public bool IsOrthogonalTo(ILinearObject obj)\n        {\n            Vector3d v = obj.Direction;\n            if ((this._coord != v._coord))\n                v = v.ConvertTo(this._coord);\n\n            double this_norm = this.Norm;\n            double v_norm = v.Norm;\n            return GeometRi3D.AlmostEqual(Abs(this * v) / (this_norm * v_norm), 0.0);\n\n        }\n\n        /// <summary>\n        /// Check if two objects are parallel\n        /// </summary>\n        public bool IsParallelTo(IPlanarObject obj)\n        {\n            return this.Direction.IsOrthogonalTo(obj.Normal);\n        }\n\n        /// <summary>\n        /// Check if two objects are NOT parallel\n        /// </summary>\n        public bool IsNotParallelTo(IPlanarObject obj)\n        {\n            return ! this.Direction.IsOrthogonalTo(obj.Normal);\n        }\n\n        /// <summary>\n        /// Check if two objects are orthogonal\n        /// </summary>\n        public bool IsOrthogonalTo(IPlanarObject obj)\n        {\n            return this.Direction.IsParallelTo(obj.Normal);\n        }\n        #endregion\n\n\n        /// <summary>\n        /// Point, represented by vector starting in origin\n        /// </summary>\n        public Point3d ToPoint\n        {\n            get { return new Point3d(val[0], val[1], val[2], _coord); }\n        }\n\n        /// <summary>\n        /// Return a normalized vector\n        /// </summary>\n        public Vector3d Normalized\n        {\n            get\n            {\n                CheckFields();\n                if (_normalized == null)\n                {\n                _normalized = this.Copy();\n                _normalized.Normalize();\n                }\n                return _normalized;\n            }\n        }\n\n        /// <summary>\n        /// Normalize the current vector\n        /// </summary>\n        public void Normalize()\n        {\n            double tmp = 1.0 / this.Norm;\n            val[0] = val[0] * tmp;\n            val[1] = val[1] * tmp;\n            val[2] = val[2] * tmp;\n            _norm = 1.0; //if we do not reset the _norm field, it is wrongly kept to it's original value (before it has been normalized)\n        }\n\n        public Vector3d Add(double a)\n        {\n            Vector3d tmp = this.Copy();\n            tmp[0] += a;\n            tmp[1] += a;\n            tmp[2] += a;\n            return tmp;\n        }\n        public Vector3d Add(Vector3d v)\n        {\n            if ((this._coord != v._coord))\n                v = v.ConvertTo(this._coord);\n            Vector3d tmp = this.Copy();\n            tmp[0] += v.X;\n            tmp[1] += v.Y;\n            tmp[2] += v.Z;\n            return tmp;\n        }\n        public Vector3d Subtract(double a)\n        {\n            Vector3d tmp = this.Copy();\n            tmp[0] -= a;\n            tmp[1] -= a;\n            tmp[2] -= a;\n            return tmp;\n        }\n        public Vector3d Subtract(Vector3d v)\n        {\n            if ((this._coord != v._coord))\n                v = v.ConvertTo(this._coord);\n            //Vector3d tmp = this.Copy();\n            //tmp[0] -= v.X;\n            //tmp[1] -= v.Y;\n            //tmp[2] -= v.Z;\n            //return tmp;\n            return new Vector3d(this.X - v.X, this.Y - v.Y, this.Z - v.Z, _coord);\n        }\n        public Vector3d Mult(double a)\n        {\n            //Vector3d tmp = this.Copy();\n            //tmp[0] *= a;\n            //tmp[1] *= a;\n            //tmp[2] *= a;\n            //return tmp;\n            return new Vector3d(this.X * a, this.Y * a, this.Z * a, _coord);\n        }\n\n        /// <summary>\n        /// Dot product of two vectors\n        /// </summary>\n        public double Dot(Vector3d v)\n        {\n            if ((this._coord != v._coord))\n                v = v.ConvertTo(this._coord);\n            return this.val[0] * v.val[0] + this.val[1] * v.val[1] + this.val[2] * v.val[2];\n        }\n        internal double Dot(Point3d v)\n        {\n            if ((this._coord != v._coord))\n                v = v.ConvertTo(this._coord);\n            return this.val[0] * v.X + this.val[1] * v.Y + this.val[2] * v.Z;\n        }\n\n        //public IVector Subtract(IVector v)\n        //{\n        //    return new Point3d(this.X - v.X, this.Y - v.Y, this.Z - v.Z, _coord);\n        //}\n        //public double Dot(IVector v)\n        //{\n        //    return this.X * v.X + this.Y * v.Y + this.Z * v.Z;\n        //}\n\n        /// <summary>\n        /// Cross product of two vectors\n        /// </summary>\n        public Vector3d Cross(Vector3d v)\n        {\n            if ((this._coord != v._coord))\n                v = v.ConvertTo(this._coord);\n            double x = this.Y * v.Z - this.Z * v.Y;\n            double y = this.Z * v.X - this.X * v.Z;\n            double z = this.X * v.Y - this.Y * v.X;\n            return new Vector3d(x, y, z, _coord); ;\n        }\n\n        /// <summary>\n        /// Convert vector to reference coordinate system.\n        /// </summary>\n        public Vector3d ConvertTo(Coord3d coord)\n        {\n            Vector3d v1 = this.Copy();\n            v1 = v1.ConvertToGlobal();\n            if (coord != null && !object.ReferenceEquals(coord, Coord3d.GlobalCS))\n            {\n                v1 = coord.Axes * v1;\n                v1._coord = coord;\n            }\n            return v1;\n        }\n\n        /// <summary>\n        /// Convert vector to global coordinate system\n        /// </summary>\n        public Vector3d ConvertToGlobal()\n        {\n            if (_coord == null || object.ReferenceEquals(_coord, Coord3d.GlobalCS))\n            {\n                return this.Copy();\n            }\n            else\n            {\n                Vector3d v = this.Copy();\n                v = _coord.Axes.Transpose() * v;\n                v._coord = Coord3d.GlobalCS;\n                return v;\n            }\n        }\n\n        #region \"AngleTo\"\n        /// <summary>\n        /// Angle between two objects in radians (0 &lt; angle &lt; Pi)\n        /// </summary>\n        public double AngleTo(ILinearObject obj)\n        {\n            return GeometRi3D.GetAngle(this, obj);\n        }\n        /// <summary>\n        /// Angle between two objects in degrees (0 &lt; angle &lt; 180)\n        /// </summary>\n        public double AngleToDeg(ILinearObject obj)\n        {\n            return AngleTo(obj) * 180 / PI;\n        }\n\n        /// <summary>\n        /// Angle between two objects in radians (0 &lt; angle &lt; Pi)\n        /// </summary>\n        public double AngleTo(IPlanarObject obj)\n        {\n            return GeometRi3D.GetAngle(this, obj);\n        }\n        /// <summary>\n        /// Angle between two objects in degrees (0 &lt; angle &lt; 180)\n        /// </summary>\n        public double AngleToDeg(IPlanarObject obj)\n        {\n            return AngleTo(obj) * 180 / PI;\n        }\n        #endregion\n\n        /// <summary>\n        /// Return projection of the current vector to the second vector\n        /// </summary>\n        public Vector3d ProjectionTo(Vector3d v)\n        {\n            if ((this._coord != v._coord))\n                v = v.ConvertTo(this._coord);\n            return (this * v) / (v * v) * v;\n        }\n\n        /// <summary>\n        /// Return arbitrary vector, orthogonal to the current vector\n        /// </summary>\n        public Vector3d OrthogonalVector\n        {\n            get\n            {\n                if (Abs(this.X) <= Abs(this.Y) && Abs(this.X) <= Abs(this.Z))\n                {\n                    return new Vector3d(0, this.Z, -this.Y, this.Coord);\n                }\n                else if (Abs(this.Y) <= Abs(this.X) && Abs(this.Y) <= Abs(this.Z))\n                {\n                    return new Vector3d(this.Z, 0, -this.X, this.Coord);\n                }\n                else\n                {\n                    return new Vector3d(this.Y, -this.X, 0, this.Coord);\n                }\n            }\n        }\n\n        #region \"RotateReflect\"\n        /// <summary>\n        /// Rotate vector by a given rotation matrix\n        /// </summary>\n        [System.Obsolete(\"use Rotation object: this.Rotate(Rotation r)\")]\n        public Vector3d Rotate(Matrix3d m)\n        {\n            return m * this;\n        }\n\n        /// <summary>\n        /// Rotate vector\n        /// </summary>\n        public Vector3d Rotate(Rotation r)\n        {\n            if (this._coord != r.Coord) r = r.ConvertTo(this._coord);\n            return r.ToRotationMatrix * this;\n        }\n\n        /// <summary>\n        /// Reflect vector in given point\n        /// </summary>\n        public Vector3d ReflectIn(Point3d p)\n        {\n            return -this;\n        }\n\n        /// <summary>\n        /// Reflect vector in given line\n        /// </summary>\n        public Vector3d ReflectIn(Line3d l)\n        {\n            Point3d p1 = new Point3d(0, 0, 0, this._coord);\n            Point3d p2 = p1.Translate(this);\n            return new Vector3d(p1.ReflectIn(l), p2.ReflectIn(l));\n        }\n\n        /// <summary>\n        /// Reflect vector in given plane\n        /// </summary>\n        public Vector3d ReflectIn(Plane3d s)\n        {\n            Point3d p1 = new Point3d(0, 0, 0, this._coord);\n            Point3d p2 = p1.Translate(this);\n            return new Vector3d(p1.ReflectIn(s), p2.ReflectIn(s));\n        }\n        #endregion\n\n        /// <summary>\n        /// Determines whether two objects are equal.\n        /// </summary>\n        public override bool Equals(object obj)\n        {\n            if (obj == null || (!object.ReferenceEquals(this.GetType(), obj.GetType())))\n            {\n                return false;\n            }\n            Vector3d v = (Vector3d)obj;\n            if ((this._coord != v.Coord))\n                v = v.ConvertTo(_coord);\n\n            if (GeometRi3D.UseAbsoluteTolerance)\n            {\n                return Abs(this.X - v.X) + Abs(this.Y - v.Y) + Abs(this.Z - v.Z) < GeometRi3D.Tolerance;\n            }\n            else\n            {\n                return (Abs(this.X - v.X) + Abs(this.Y - v.Y) + Abs(this.Z - v.Z)) / this.Norm < GeometRi3D.Tolerance;\n            }\n\n        }\n\n        /// <summary>\n        /// Returns the hashcode for the object.\n        /// </summary>\n        public override int GetHashCode()\n        {\n            return GeometRi3D.HashFunction(val[0].GetHashCode(), val[1].GetHashCode(), val[2].GetHashCode(), _coord.GetHashCode());\n        }\n\n        /// <summary>\n        /// String representation of an object in global coordinate system.\n        /// </summary>\n        public override String ToString()\n        {\n            return ToString(Coord3d.GlobalCS);\n        }\n\n        /// <summary>\n        /// String representation of an object in reference coordinate system.\n        /// </summary>\n        public String ToString(Coord3d coord)\n        {\n            if (coord == null) { coord = Coord3d.GlobalCS; }\n            Vector3d v = this.ConvertTo(coord);\n            return string.Format(\"Vector3d -> ({0,10:g5}, {1,10:g5}, {2,10:g5})\", v.X, v.Y, v.Z);\n        }\n\n        // Operators overloads\n        //-----------------------------------------------------------------\n        // \"+\"\n        public static Vector3d operator +(Vector3d v, Vector3d a)\n        {\n            return v.Add(a);\n        }\n        // \"-\"\n        public static Vector3d operator -(Vector3d v)\n        {\n            return v.Mult(-1.0);\n        }\n        public static Vector3d operator -(Vector3d v, Vector3d a)\n        {\n            return v.Subtract(a);\n        }\n        // \"*\"\n        public static Vector3d operator *(Vector3d v, double a)\n        {\n            return v.Mult(a);\n        }\n        public static Vector3d operator /(Vector3d v, double a)\n        {\n            return v.Mult(1.0/a);\n        }\n        public static Vector3d operator *(double a, Vector3d v)\n        {\n            return v.Mult(a);\n        }\n        /// <summary>\n        /// Dot product of two vectors\n        /// </summary>\n        public static double operator *(Vector3d v, Vector3d a)\n        {\n            return v.Dot(a);\n        }\n\n        public static bool operator ==(Vector3d v1, Vector3d v2)\n        {\n            if (object.ReferenceEquals(v1, null))\n                return object.ReferenceEquals(v2, null);\n            return v1.Equals(v2);\n        }\n        public static bool operator !=(Vector3d v1, Vector3d v2)\n        {\n            if (object.ReferenceEquals(v1, null))\n                return !object.ReferenceEquals(v2, null);\n            return !v1.Equals(v2);\n        }\n\n    }\n}\n\n\n"
  },
  {
    "path": "GeometRi.Benchmarks/GeometRi.Benchmarks.csproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <Import Project=\"$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props\" Condition=\"Exists('$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props')\" />\n  <PropertyGroup>\n    <Configuration Condition=\" '$(Configuration)' == '' \">Debug</Configuration>\n    <Platform Condition=\" '$(Platform)' == '' \">AnyCPU</Platform>\n    <ProjectGuid>{BBB4B097-55D3-4135-AF02-471E007E3FDB}</ProjectGuid>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>GeometRi.Benchmarks</RootNamespace>\n    <AssemblyName>GeometRi.Benchmarks</AssemblyName>\n    <TargetFrameworkVersion>v4.8</TargetFrameworkVersion>\n    <FileAlignment>512</FileAlignment>\n    <Deterministic>true</Deterministic>\n    <TargetFrameworkProfile />\n  </PropertyGroup>\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' \">\n    <PlatformTarget>AnyCPU</PlatformTarget>\n    <DebugSymbols>true</DebugSymbols>\n    <DebugType>full</DebugType>\n    <Optimize>false</Optimize>\n    <OutputPath>bin\\Debug\\</OutputPath>\n    <DefineConstants>DEBUG;TRACE</DefineConstants>\n    <ErrorReport>prompt</ErrorReport>\n    <WarningLevel>4</WarningLevel>\n    <Prefer32Bit>false</Prefer32Bit>\n  </PropertyGroup>\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' \">\n    <PlatformTarget>AnyCPU</PlatformTarget>\n    <DebugType>pdbonly</DebugType>\n    <Optimize>true</Optimize>\n    <OutputPath>bin\\Release\\</OutputPath>\n    <DefineConstants>TRACE</DefineConstants>\n    <ErrorReport>prompt</ErrorReport>\n    <WarningLevel>4</WarningLevel>\n    <Prefer32Bit>false</Prefer32Bit>\n  </PropertyGroup>\n  <ItemGroup>\n    <Reference Include=\"GeometRi\">\n      <HintPath>..\\GeometRi\\bin\\Release\\net20\\GeometRi.dll</HintPath>\n    </Reference>\n    <Reference Include=\"System\" />\n    <Reference Include=\"System.Core\" />\n    <Reference Include=\"System.Xml.Linq\" />\n    <Reference Include=\"System.Data.DataSetExtensions\" />\n    <Reference Include=\"Microsoft.CSharp\" />\n    <Reference Include=\"System.Data\" />\n    <Reference Include=\"System.Xml\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Compile Include=\"Program.cs\" />\n    <Compile Include=\"Properties\\AssemblyInfo.cs\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"app.config\" />\n  </ItemGroup>\n  <Import Project=\"$(MSBuildToolsPath)\\Microsoft.CSharp.targets\" />\n</Project>"
  },
  {
    "path": "GeometRi.Benchmarks/Program.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\nusing System.Collections.Generic;\nusing GeometRi;\n\nnamespace GeometRi.Benchmarks\n{\n    class IntersectionBenchmark\n    {\n        static void Main(string[] args)\n        {\n\n            //Profile(\"Test\", 10000, () =>\n            //{\n            //    Box3d box = new Box3d(new Point3d(0.5, 0.5, 0.5), 1, 1, 1);\n            //    Circle3d c = new Circle3d(new Point3d(0.957494668177094, 1.08987119472114, -0.11622424522239),\n            //                              0.154926580712558,\n            //                              new Vector3d(0.362303959251271, 0.267138656415756, 0.892957322249635));\n            //    object obj = c.Intersects(box);\n            //});\n\n            //Profile(\"Test\", 20000, () =>\n            //{\n            //    Circle3d c1 = new Circle3d(new Point3d(0, 0, 0), 5, new Vector3d(0, 0, 1));\n            //    Circle3d c2 = new Circle3d(new Point3d(11, 0, 0), 5, new Vector3d(0, 0, 1));\n\n            //    bool t1 = GeometRi3D.AlmostEqual(c1.DistanceTo(c2), 1);\n\n            //    c2 = new Circle3d(new Point3d(11, 0, 0), 5, new Vector3d(0, 2, 1));\n            //    bool t2 = GeometRi3D.AlmostEqual(c1.DistanceTo(c2), 1);\n\n            //});\n\n            //Circle3d c = new Circle3d(new Point3d(2, 22, 43), 5, new Vector3d(0, 0, 2));\n            //Point3d p = new Point3d(12, -22, -43);\n            //Profile(\"Test\", 2000000, () =>\n            //{\n            //    double dist = p.DistanceTo(c);\n\n            //});\n\n\n            //Circle3d c = new Circle3d(new Point3d(2, 22, 43), 5, new Vector3d(0, 0, 2));\n            //Point3d p1 = new Point3d(12, -22, -43);\n            //Point3d p2 = new Point3d(3, 14, -6);\n            //Point3d p3 = new Point3d(-12, 11, 4);\n            //Triangle t = new Triangle(p1, p2, p3);\n            //Profile(\"Test\", 200000, () =>\n            //{\n            //    bool test = c.Intersects(t);\n            //});\n\n            //Line3d s = new Line3d(new Point3d(1, 2, 0), new Vector3d(-5, 7, 0));\n            //Point3d p1 = new Point3d(12, -22, 0);\n            //Point3d p2 = new Point3d(3, 14, 0);\n            //Point3d p3 = new Point3d(-12, 11, 0);\n            //Triangle t = new Triangle(p1, p2, p3);\n            //Circle3d c1 = new Circle3d(new Point3d(2, 22, 43), 50, new Vector3d(0, 0, 2));\n            //Circle3d c2 = new Circle3d(new Point3d(22, -3, 8), 50, new Vector3d(-1, 2, -4));\n            //Box3d box = new Box3d();\n            //Circle3d c3 = new Circle3d(new Point3d(0.3, 0.55, 0.3), 0.1, new Vector3d(0, 0, 2));\n            //Sphere sph = new Sphere(new Point3d(2.3, 1.55, 0.3), 0.1);\n            //double dist1 = sph.DistanceTo(box);\n\n            //List<ConvexPolyhedron> list = new List<ConvexPolyhedron>();\n            //Random rnd = new Random();\n            //for (int i=0; i < 5; i++)\n            //{\n            //    ConvexPolyhedron cp = ConvexPolyhedron.Octahedron();\n            //    Rotation r = new Rotation(new Vector3d(rnd.NextDouble(), rnd.NextDouble(), rnd.NextDouble()), rnd.NextDouble());\n            //    cp = cp.Rotate(r, cp.Center);\n            //    cp = cp.Translate(new Vector3d(5 * rnd.NextDouble(), 5 * rnd.NextDouble(), 5 * rnd.NextDouble()));\n            //    list.Add(cp);\n            //}\n            //for (int i = 0; i < 5; i++)\n            //{\n            //    ConvexPolyhedron cp = ConvexPolyhedron.Icosahedron();\n            //    Rotation r = new Rotation(new Vector3d(rnd.NextDouble(), rnd.NextDouble(), rnd.NextDouble()), rnd.NextDouble());\n            //    cp = cp.Rotate(r, cp.Center);\n            //    cp = cp.Translate(new Vector3d(5 * rnd.NextDouble(), 5 * rnd.NextDouble(), 5 * rnd.NextDouble()));\n            //    list.Add(cp);\n            //}\n            //for (int i = 0; i < 5; i++)\n            //{\n            //    ConvexPolyhedron cp = ConvexPolyhedron.Dodecahedron();\n            //    Rotation r = new Rotation(new Vector3d(rnd.NextDouble(), rnd.NextDouble(), rnd.NextDouble()), rnd.NextDouble());\n            //    cp = cp.Rotate(r, cp.Center);\n            //    cp = cp.Translate(new Vector3d(5 * rnd.NextDouble(), 5 * rnd.NextDouble(), 5 * rnd.NextDouble()));\n            //    list.Add(cp);\n            //}\n\n            //Profile(\"Test2\", 50, () =>\n            //{\n            //    foreach(ConvexPolyhedron cp1 in list)\n            //    {\n            //        foreach(ConvexPolyhedron cp2 in list)\n            //        {\n            //            Point3d pp1 = new Point3d();\n            //            Point3d pp2 = new Point3d();\n            //            double dist = cp1.DistanceTo(cp2, out pp1, out pp2);\n            //        }\n            //    }\n            //});\n\n\n            //Random rnd = new Random();\n            //List<Point3d> list = new List<Point3d>();\n            //for (int i = 0; i < 300000; i++)\n            //{\n            //    Rotation r = new Rotation(new Vector3d(rnd.NextDouble(), rnd.NextDouble(), rnd.NextDouble()), rnd.NextDouble());\n            //    Point3d origin = new Point3d(rnd.NextDouble(), rnd.NextDouble(), rnd.NextDouble());\n            //    Coord3d coord = new Coord3d(origin, r.ToRotationMatrix.Column1, r.ToRotationMatrix.Column2);\n            //    list.Add(new Point3d(rnd.NextDouble(), rnd.NextDouble(), rnd.NextDouble(), coord));\n            //}\n\n            //Profile(\"Test2\", 5, () =>\n            //{\n            //    foreach (Point3d p in list)\n            //    {\n            //        Point3d p2 = p.ConvertToGlobal();\n            //    }\n            //});\n\n\n            TestSegmentPolyhedronDistance();\n\n            Console.ReadLine();\n        }\n\n        static void Profile(string description, int iterations, Action action)\n        {\n            try\n            {\n                Console.WriteLine($\"Running benchmark '{description}' for {iterations} iterations... \");\n\n                // clean up\n                GC.Collect();\n                GC.WaitForPendingFinalizers();\n\n                // warm up \n                action.Invoke();\n\n                Stopwatch watch = Stopwatch.StartNew();\n                for (int i = 0; i < iterations; i++)\n                {\n                    action.Invoke();\n                }\n                watch.Stop();\n                Console.Write(description);\n                Console.WriteLine(\"Time Elapsed: {0} ms\", watch.ElapsedMilliseconds);\n                Console.WriteLine($\"Time per iteration: {watch.ElapsedMilliseconds / iterations} ms.\");\n            }\n            catch (OutOfMemoryException)\n            {\n                Console.WriteLine(\"Out of memory!\");\n            }\n\n        }\n\n        static void TestPointTriangleDistance()\n        {\n            Random rnd = new Random();\n            List<Point3d> list = new List<Point3d>();\n            for (int i = 0; i < 1000000; i++)\n            {\n                list.Add(new Point3d(rnd.NextDouble(), rnd.NextDouble(), rnd.NextDouble()));\n            }\n            Triangle t = new Triangle(new Point3d(0.2, 0.1, 0.05), new Point3d(-0.2, 0.2, -0.1), new Point3d(0.03, -0.1, 0.1));\n\n            Profile(\"Test\", 4, () =>\n            {\n                double dist = 0;\n                foreach (Point3d p in list)\n                {\n                    dist += t.DistanceTo(p);\n                }\n                Console.WriteLine(dist);\n            });\n\n\n\n            Profile(\"Test2\", 4, () =>\n            {\n                double dist = 0;\n                foreach (Point3d p in list)\n                {\n                    dist += t.DistanceTo(p);\n                }\n                Console.WriteLine(dist);\n            });\n\n\n\n            Console.ReadLine();\n        }\n\n\n        static void TestSegmentTriangleDistance()\n        {\n            Random rnd = new Random();\n            List<Segment3d> list = new List<Segment3d>();\n            for (int i = 0; i < 500000; i++)\n            {\n                list.Add(new Segment3d(new Point3d(rnd.NextDouble() - 0.5, rnd.NextDouble() - 0.5, rnd.NextDouble() - 0.5),\n                                       new Point3d(rnd.NextDouble() - 0.5, rnd.NextDouble() - 0.5, rnd.NextDouble() - 0.5)));\n            }\n            Triangle t = new Triangle(new Point3d(0.2, 0.1, 0.05), new Point3d(-0.2, 0.2, -0.1), new Point3d(0.03, -0.1, 0.1));\n\n\n\n            Profile(\"Test\", 4, () =>\n            {\n                double dist = 0;\n                foreach (Segment3d s in list)\n                {\n                    dist += t.DistanceTo(s);\n                }\n                Console.WriteLine(dist);\n            });\n\n\n\n            Console.ReadLine();\n        }\n\n        static void TestSegmentPolyhedronDistance()\n        {\n            Random rnd = new Random();\n            List<Segment3d> list = new List<Segment3d>();\n            for (int i = 0; i < 200000; i++)\n            {\n                list.Add(new Segment3d(new Point3d(rnd.NextDouble() - 0.5, rnd.NextDouble() - 0.5, rnd.NextDouble() - 0.5),\n                                       new Point3d(rnd.NextDouble() - 0.5, rnd.NextDouble() - 0.5, rnd.NextDouble() - 0.5)));\n            }\n            ConvexPolyhedron cp = ConvexPolyhedron.RhombicDodecahedron().Scale(0.1);\n\n\n\n            Profile(\"Test\", 4, () =>\n            {\n                double dist = 0;\n                foreach (Segment3d s in list)\n                {\n                    dist += cp.DistanceTo(s);\n                }\n                Console.WriteLine(dist);\n            });\n\n\n\n\n            Console.ReadLine();\n        }\n\n        static void TestTrianglePolyhedronDistance()\n        {\n            Random rnd = new Random();\n            List<Triangle> list = new List<Triangle>();\n            for (int i = 0; i < 9000; i++)\n            {\n                list.Add(new Triangle(new Point3d(rnd.NextDouble() - 0.5, rnd.NextDouble() - 0.5, rnd.NextDouble() - 0.5),\n                                      new Point3d(rnd.NextDouble() - 0.5, rnd.NextDouble() - 0.5, rnd.NextDouble() - 0.5),\n                                      new Point3d(rnd.NextDouble() - 0.5, rnd.NextDouble() - 0.5, rnd.NextDouble() - 0.5)));\n            }\n            ConvexPolyhedron cp = ConvexPolyhedron.RhombicDodecahedron().Scale(0.1);\n            //ConvexPolyhedron cp = ConvexPolyhedron.Cube(new Point3d(0.05, 0.15, 0.05), new Point3d(0.55, 0.75, 0.15));\n\n\n\n            Profile(\"Test\", 4, () =>\n            {\n                double dist = 0;\n                foreach (Triangle t in list)\n                {\n                    dist += cp.DistanceTo(t);\n                }\n                Console.WriteLine(dist);\n            });\n\n\n\n\n\n\n            Console.ReadLine();\n        }\n    }\n}\n"
  },
  {
    "path": "GeometRi.Benchmarks/Properties/AssemblyInfo.cs",
    "content": "﻿using System.Reflection;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\n\n// General Information about an assembly is controlled through the following\n// set of attributes. Change these attribute values to modify the information\n// associated with an assembly.\n[assembly: AssemblyTitle(\"GeometRi.Benchmarks\")]\n[assembly: AssemblyDescription(\"\")]\n[assembly: AssemblyConfiguration(\"\")]\n[assembly: AssemblyCompany(\"HP Inc.\")]\n[assembly: AssemblyProduct(\"GeometRi.Benchmarks\")]\n[assembly: AssemblyCopyright(\"Copyright © HP Inc. 2019\")]\n[assembly: AssemblyTrademark(\"\")]\n[assembly: AssemblyCulture(\"\")]\n\n// Setting ComVisible to false makes the types in this assembly not visible\n// to COM components.  If you need to access a type in this assembly from\n// COM, set the ComVisible attribute to true on that type.\n[assembly: ComVisible(false)]\n\n// The following GUID is for the ID of the typelib if this project is exposed to COM\n[assembly: Guid(\"bbb4b097-55d3-4135-af02-471e007e3fdb\")]\n\n// Version information for an assembly consists of the following four values:\n//\n//      Major Version\n//      Minor Version\n//      Build Number\n//      Revision\n//\n// You can specify all the values or you can default the Build and Revision Numbers\n// by using the '*' as shown below:\n// [assembly: AssemblyVersion(\"1.0.*\")]\n[assembly: AssemblyVersion(\"1.0.0.0\")]\n[assembly: AssemblyFileVersion(\"1.0.0.0\")]\n"
  },
  {
    "path": "GeometRi.Benchmarks/app.config",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<configuration>\n<startup><supportedRuntime version=\"v4.0\" sku=\".NETFramework,Version=v4.8\"/></startup></configuration>\n"
  },
  {
    "path": "GeometRi.Example/GeometRi.Example.csproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <Import Project=\"$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props\" Condition=\"Exists('$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props')\" />\n  <PropertyGroup>\n    <Configuration Condition=\" '$(Configuration)' == '' \">Debug</Configuration>\n    <Platform Condition=\" '$(Platform)' == '' \">AnyCPU</Platform>\n    <ProjectGuid>{3D086E96-C1D2-42DB-9EED-300C3A9BBAA8}</ProjectGuid>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>GeometRi.Example</RootNamespace>\n    <AssemblyName>GeometRi.Example</AssemblyName>\n    <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>\n    <FileAlignment>512</FileAlignment>\n    <TargetFrameworkProfile />\n  </PropertyGroup>\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' \">\n    <PlatformTarget>AnyCPU</PlatformTarget>\n    <DebugSymbols>true</DebugSymbols>\n    <DebugType>full</DebugType>\n    <Optimize>false</Optimize>\n    <OutputPath>bin\\Debug\\</OutputPath>\n    <DefineConstants>DEBUG;TRACE</DefineConstants>\n    <ErrorReport>prompt</ErrorReport>\n    <WarningLevel>4</WarningLevel>\n    <Prefer32Bit>false</Prefer32Bit>\n  </PropertyGroup>\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' \">\n    <PlatformTarget>AnyCPU</PlatformTarget>\n    <DebugType>pdbonly</DebugType>\n    <Optimize>true</Optimize>\n    <OutputPath>bin\\Release\\</OutputPath>\n    <DefineConstants>TRACE</DefineConstants>\n    <ErrorReport>prompt</ErrorReport>\n    <WarningLevel>4</WarningLevel>\n    <Prefer32Bit>false</Prefer32Bit>\n  </PropertyGroup>\n  <ItemGroup>\n    <Reference Include=\"System\" />\n    <Reference Include=\"System.Data\" />\n    <Reference Include=\"System.Xml\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Compile Include=\"Program.cs\" />\n    <Compile Include=\"Properties\\AssemblyInfo.cs\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"app.config\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"..\\GeometRi\\GeometRi.csproj\">\n      <Project>{f73e450b-8f34-4b6b-8bf3-b7a17d9f52c5}</Project>\n      <Name>GeometRi</Name>\n    </ProjectReference>\n  </ItemGroup>\n  <Import Project=\"$(MSBuildToolsPath)\\Microsoft.CSharp.targets\" />\n</Project>"
  },
  {
    "path": "GeometRi.Example/Program.cs",
    "content": "﻿using System;\nusing System.Runtime;\nusing GeometRi;\n\n\nnamespace GeometRi_Example\n{\n    class Program\n    {\n        public static void Main()\n        {\n            // Examples of basic operations with GeometRi\n\n            // Global coordinate system is created automatically and can be accessed as \"Coord3d.GlobalCS\"\n            Console.WriteLine(\"Number of defined coordinate systems: {0}\", Coord3d.Counts);\n            Console.WriteLine();\n            Console.WriteLine(\"Default coordinate system: \");\n            Console.WriteLine(Coord3d.GlobalCS.ToString());\n\n\n\n            Console.WriteLine();\n            Console.WriteLine();\n            Console.WriteLine(\"!!! Find intersection of plane with line !!!\");\n\n            // Define point and vector in global CS\n            Point3d p1 = new Point3d(1, -5, -1);\n            Vector3d v1 = new Vector3d(-2, 3, 4);\n\n            // Define line using point and vector\n            Line3d l1 = new Line3d(p1, v1);\n\n            // Define plane using general equation in 3D space in the form \"A*x+B*y+C*z+D=0\"\n            Plane3d s1 = new Plane3d(-2, 2, 3, -29);\n\n            // Find the intersection of line with plane.\n            // The results could be point, line or nothing, therefore get result as general object\n            // and determine it's type.\n            object obj = l1.IntersectionWith(s1);\n            if (obj != null)\n            {\n                if (obj.GetType() == typeof(Line3d))\n                {\n                    Console.WriteLine(\"Intersection is line\");\n                    Line3d l2 = (Line3d)obj;\n                    Console.WriteLine(l2.ToString());\n                }\n                else if (obj.GetType() == typeof(Point3d))\n                {\n                    Console.WriteLine(\"Intersection is point\");\n                    Point3d p2 = (Point3d)obj;\n                    Console.WriteLine(p2.ToString());\n                }\n            }\n\n            // Short variant\n            // Will cause \"InvalidCastException\" if the intersection is not a point\n            Point3d p3 = (Point3d)l1.IntersectionWith(s1);\n            Console.WriteLine(p3.ToString());\n\n\n\n\n            Console.ReadLine();\n\n\n        }\n\n    }\n}\n\n"
  },
  {
    "path": "GeometRi.Example/Properties/AssemblyInfo.cs",
    "content": "﻿using System.Reflection;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\n\n// General Information about an assembly is controlled through the following\n// set of attributes. Change these attribute values to modify the information\n// associated with an assembly.\n[assembly: AssemblyTitle(\"GeometRi.Example\")]\n[assembly: AssemblyDescription(\"\")]\n[assembly: AssemblyConfiguration(\"\")]\n[assembly: AssemblyCompany(\"\")]\n[assembly: AssemblyProduct(\"GeometRi.Example\")]\n[assembly: AssemblyCopyright(\"Copyright ©  2017\")]\n[assembly: AssemblyTrademark(\"\")]\n[assembly: AssemblyCulture(\"\")]\n\n// Setting ComVisible to false makes the types in this assembly not visible\n// to COM components.  If you need to access a type in this assembly from\n// COM, set the ComVisible attribute to true on that type.\n[assembly: ComVisible(false)]\n\n// The following GUID is for the ID of the typelib if this project is exposed to COM\n[assembly: Guid(\"3d086e96-c1d2-42db-9eed-300c3a9bbaa8\")]\n\n// Version information for an assembly consists of the following four values:\n//\n//      Major Version\n//      Minor Version\n//      Build Number\n//      Revision\n//\n// You can specify all the values or you can default the Build and Revision Numbers\n// by using the '*' as shown below:\n// [assembly: AssemblyVersion(\"1.0.*\")]\n[assembly: AssemblyVersion(\"1.0.0.0\")]\n[assembly: AssemblyFileVersion(\"1.0.0.0\")]\n"
  },
  {
    "path": "GeometRi.Example/app.config",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<configuration>\n<startup><supportedRuntime version=\"v4.0\" sku=\".NETFramework,Version=v4.6.1\"/></startup></configuration>\n"
  },
  {
    "path": "GeometRi.Example.FSharp/App.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<configuration>\n    <startup> \n        <supportedRuntime version=\"v4.0\" sku=\".NETFramework,Version=v4.6.1\" />\n    </startup>\n</configuration>"
  },
  {
    "path": "GeometRi.Example.FSharp/AssemblyInfo.fs",
    "content": "﻿namespace GeometRi.Example.FSharp.AssemblyInfo\n\nopen System.Reflection\nopen System.Runtime.CompilerServices\nopen System.Runtime.InteropServices\n\n// General Information about an assembly is controlled through the following\n// set of attributes. Change these attribute values to modify the information\n// associated with an assembly.\n[<assembly: AssemblyTitle(\"GeometRi.Example.FSharp\")>]\n[<assembly: AssemblyDescription(\"\")>]\n[<assembly: AssemblyConfiguration(\"\")>]\n[<assembly: AssemblyCompany(\"\")>]\n[<assembly: AssemblyProduct(\"GeometRi.Example.FSharp\")>]\n[<assembly: AssemblyCopyright(\"Copyright © 2018\")>]\n[<assembly: AssemblyTrademark(\"\")>]\n[<assembly: AssemblyCulture(\"\")>]\n\n// Setting ComVisible to false makes the types in this assembly not visible\n// to COM components.  If you need to access a type in this assembly from\n// COM, set the ComVisible attribute to true on that type.\n[<assembly: ComVisible(false)>]\n\n// The following GUID is for the ID of the typelib if this project is exposed to COM\n[<assembly: Guid(\"d59a9e53-d080-4ae9-b5cb-e60f2bf5e634\")>]\n\n// Version information for an assembly consists of the following four values:\n//\n//       Major Version\n//       Minor Version\n//       Build Number\n//       Revision\n//\n// You can specify all the values or you can default the Build and Revision Numbers\n// by using the '*' as shown below:\n// [<assembly: AssemblyVersion(\"1.0.*\")>]\n[<assembly: AssemblyVersion(\"1.0.0.0\")>]\n[<assembly: AssemblyFileVersion(\"1.0.0.0\")>]\n\ndo\n    ()"
  },
  {
    "path": "GeometRi.Example.FSharp/GeometRi.Example.FSharp.fsproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"15.0\" DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <Import Project=\"$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props\" Condition=\"Exists('$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props')\" />\n  <PropertyGroup>\n    <Configuration Condition=\" '$(Configuration)' == '' \">Debug</Configuration>\n    <Platform Condition=\" '$(Platform)' == '' \">AnyCPU</Platform>\n    <SchemaVersion>2.0</SchemaVersion>\n    <ProjectGuid>d59a9e53-d080-4ae9-b5cb-e60f2bf5e634</ProjectGuid>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>GeometRi.Example.FSharp</RootNamespace>\n    <AssemblyName>GeometRi.Example.FSharp</AssemblyName>\n    <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>\n    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>\n    <UseStandardResourceNames>true</UseStandardResourceNames>\n    <Name>GeometRi.Example.FSharp</Name>\n  </PropertyGroup>\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' \">\n    <DebugSymbols>true</DebugSymbols>\n    <DebugType>full</DebugType>\n    <Optimize>false</Optimize>\n    <Tailcalls>false</Tailcalls>\n    <OutputPath>bin\\$(Configuration)\\</OutputPath>\n    <DefineConstants>DEBUG;TRACE</DefineConstants>\n    <WarningLevel>3</WarningLevel>\n    <PlatformTarget>AnyCPU</PlatformTarget>\n    <DocumentationFile>bin\\$(Configuration)\\$(AssemblyName).XML</DocumentationFile>\n    <Prefer32Bit>true</Prefer32Bit>\n  </PropertyGroup>\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' \">\n    <DebugType>pdbonly</DebugType>\n    <Optimize>true</Optimize>\n    <Tailcalls>true</Tailcalls>\n    <OutputPath>bin\\$(Configuration)\\</OutputPath>\n    <DefineConstants>TRACE</DefineConstants>\n    <WarningLevel>3</WarningLevel>\n    <PlatformTarget>AnyCPU</PlatformTarget>\n    <DocumentationFile>bin\\$(Configuration)\\$(AssemblyName).XML</DocumentationFile>\n    <Prefer32Bit>true</Prefer32Bit>\n  </PropertyGroup>\n  <PropertyGroup>\n    <MinimumVisualStudioVersion Condition=\"'$(MinimumVisualStudioVersion)' == ''\">11</MinimumVisualStudioVersion>\n  </PropertyGroup>\n  <PropertyGroup Condition=\" '$(FSharpTargetsPath)' == '' AND Exists('$(MSBuildExtensionsPath32)\\Microsoft\\VisualStudio\\v$(VisualStudioVersion)\\FSharp\\Microsoft.FSharp.Targets') \">\n    <FSharpTargetsPath>$(MSBuildExtensionsPath32)\\Microsoft\\VisualStudio\\v$(VisualStudioVersion)\\FSharp\\Microsoft.FSharp.Targets</FSharpTargetsPath>\n  </PropertyGroup>\n  <Import Project=\"$(FSharpTargetsPath)\" />\n  <ItemGroup>\n    <Compile Include=\"AssemblyInfo.fs\" />\n    <Compile Include=\"Program.fs\" />\n    <None Include=\"App.config\" />\n    <Content Include=\"packages.config\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Reference Include=\"FSharp.Core\">\n      <HintPath>..\\packages\\FSharp.Core.4.5.2\\lib\\net45\\FSharp.Core.dll</HintPath>\n    </Reference>\n    <Reference Include=\"mscorlib\" />\n    <Reference Include=\"System\" />\n    <Reference Include=\"System.Core\" />\n    <Reference Include=\"System.Numerics\" />\n    <Reference Include=\"System.ValueTuple\">\n      <HintPath>..\\packages\\System.ValueTuple.4.4.0\\lib\\net461\\System.ValueTuple.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n  </ItemGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"..\\GeometRi\\GeometRi.csproj\">\n      <Name>GeometRi</Name>\n      <Project>{f73e450b-8f34-4b6b-8bf3-b7a17d9f52c5}</Project>\n      <Private>True</Private>\n    </ProjectReference>\n  </ItemGroup>\n  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. \n       Other similar extension points exist, see Microsoft.Common.targets.\n  <Target Name=\"BeforeBuild\">\n  </Target>\n  <Target Name=\"AfterBuild\">\n  </Target>\n  -->\n</Project>"
  },
  {
    "path": "GeometRi.Example.FSharp/Program.fs",
    "content": "﻿open GeometRi\nopen System\n\nlet sample1() = \n    printfn \"Ptolemy's construction of a pentagon\"\n    printfn \"Draw a regular pentagon inside the circle\"\n    printfn \"\"\n\n    // We will follow the notation from \n    // https://www.cut-the-knot.org/pythagoras/pentagon.shtml\n    // Read this article for detailed description of the algorithm\n\n    // Create circle with center in point O and choose arbitrary point C on circle\n    // We will start our pentagon from this point\n    let O = Point3d(0.0, 0.0, 0.0)\n    let circle = Circle3d(O, 1.0, Vector3d(0.0, 0.0, 1.0))\n    let C = circle.ParametricForm(0.0)\n\n    // Draw a diameter through point C (point D is the opposite point of the diameter)\n    let l = Line3d(C, O)\n    let CD = l.IntersectionWith circle |> unbox<Segment3d>\n\n    // Need to check if we get the correct point\n    let D = if CD.P1 = C then CD.P2 else CD.P1\n\n    // Draw a orthogonal diameter AB\n\n    // First, draw two circles with centers in points C and D\n    // The intersection of these circles gives a line, orthogonal to the segment CD\n    let circle1 = Circle3d(C, CD.Length, circle.Normal)\n    let circle2 = Circle3d(D, CD.Length, circle.Normal)\n    let line = (circle1.IntersectionWith circle2 |> unbox<Segment3d>).ToLine\n\n    // Now find the intersection of line with our circle\n    // This gives points A and B\n    let AB = line.IntersectionWith circle |> unbox<Segment3d>\n    let A = AB.P1\n    let B = AB.P2\n\n    // Find the center point of the segment OB (this will be point M)\n    let M = (O + B) / 2.0\n\n    // Draw a circle with center in point M and radius MC\n    let radius = M.DistanceTo C\n    let tmp_circle0 = Circle3d(M, radius, circle.Normal)\n\n    // Find the intersection with diameter AB (this will be point N)\n    let ON = tmp_circle0.IntersectionWith AB |> unbox<Segment3d>\n    let N = if ON.P1 = O then ON.P2 else ON.P1\n\n    // CN is the length of the pentagon's side\n    let side_len = C.DistanceTo N \n\n    // The first point of the pentagon is point C\n    let P1 = C\n\n    // Draw a circle from point C with radius 'side_len' and this gives us two more points\n    let tmp_circle1 = Circle3d(C, side_len, circle.Normal)\n    let tmp_segment = tmp_circle1.IntersectionWith circle |> unbox<Segment3d>\n    let P2 = tmp_segment.P1\n    let P5 = tmp_segment.P2\n\n    // Repeat this two more times to get remaining points\n    let tmp_circle2 = Circle3d(P2, side_len, circle.Normal)\n    let tmp_segment2 = tmp_circle2.IntersectionWith circle |> unbox<Segment3d>\n    let P3 = if tmp_segment2.P1 = P1 then tmp_segment2.P2 else tmp_segment2.P1\n\n    let tmp_circle3 = Circle3d(P3, side_len, circle.Normal);\n    let tmp_segment3 = tmp_circle3.IntersectionWith circle |> unbox<Segment3d>\n    let P4 = if tmp_segment3.P1 = P2 then tmp_segment3.P2 else tmp_segment3.P1 \n\n    // Points P1, P2, P3, P4 and P5 define our pentagon\n    // Let's check if interion angles are equal 108 degrees (with accuracy 1e-8)\n    let angle1 = Vector3d(P1, P2).AngleToDeg(Vector3d(P1, P5))\n    let angle2 = Vector3d(P2, P1).AngleToDeg(Vector3d(P2, P3))\n    let angle3 = Vector3d(P3, P2).AngleToDeg(Vector3d(P3, P4))\n    let angle4 = Vector3d(P4, P3).AngleToDeg(Vector3d(P4, P5))\n    let angle5 = Vector3d(P5, P4).AngleToDeg(Vector3d(P5, P1))\n\n    let tolerance = 1e-8;\n    if Math.Abs(angle1 - 108.0) < tolerance &&\n       Math.Abs(angle2 - 108.0) < tolerance &&\n       Math.Abs(angle3 - 108.0) < tolerance &&\n       Math.Abs(angle4 - 108.0) < tolerance &&\n       Math.Abs(angle5 - 108.0) < tolerance \n    then\n        printfn \"Your construction is correct!\"\n        printfn \"%A\" P1\n        printfn \"%A\" P2\n        printfn \"%A\" P3\n        printfn \"%A\" P4\n        printfn \"%A\" P5\n\nlet sample2() = \n    printfn \"Rytz's construction example\"\n\n    // We will follow the notation from \n    // https://en.wikipedia.org/wiki/Rytz%27s_construction\n    // Read this article for detailed description of the algorithm\n\n    // Define arbitrary circle and plane\n    let circle = Circle3d(Point3d(2.0, 3.0, -1.0), 5.0, Vector3d(1.0, 1.0, 1.0))\n    let plane = Plane3d(Point3d(-1.0, -5.0, 0.0), Vector3d(3.0, 0.0, 1.0))\n\n    // Get two points on the circle at orthogonal diameters\n    let d1 = circle.ParametricForm 0.0\n    let d2 = circle.ParametricForm(Math.PI / 2.0)\n\n    //Project onto plane\n    let C = circle.Center.ProjectionTo plane\n    let P = d1.ProjectionTo plane\n    let Q = d2.ProjectionTo plane\n\n    // Rotate point P by 90 degrees\n    let r = Rotation(plane.Normal, Math.PI / 2.0)\n    let P_prime = P.Rotate(r, C)\n\n    // Determine the center D of the line segment P'-Q\n    let D = (P_prime + Q) / 2.0\n\n    // Draw the circle with center D throuugh point C\n    let radius = D.DistanceTo C\n    let circle_DC = Circle3d(D, radius, plane.Normal)\n\n    // Intersect the circle and the line P'-Q. Intersection points are A and B.\n    // (some additional treatment is needed when circle is parallel to plane,\n    // not going to do it here)\n    let line = Line3d(P_prime, Q)\n    let AB = line.IntersectionWith(circle_DC) |> unbox<Segment3d>\n    let A = AB.P1\n    let B = AB.P2\n\n    // Find the length of semi-axes\n    let semi_axis_a = Q.DistanceTo A\n    let semi_axis_b = Q.DistanceTo B\n\n    // Find the direction of semi-axes\n    let tvec_CA = Vector3d(C, A)\n    let tvec_CB = Vector3d(C, B)\n\n    // renormalize vectors\n    let vec_CA = semi_axis_b * tvec_CA.Normalized;\n    let vec_CB = semi_axis_a * tvec_CB.Normalized;\n\n    // Now, construct the projection\n    let ellipse = Ellipse(C, vec_CA, vec_CB)\n\n    // Compare with more efficient numerical algorithm\n    if ellipse = circle.ProjectionTo plane then\n        printfn \"Your construction is correct!\"\n        printfn \"%A\" ellipse\n\nlet sample3() = \n    printfn \"Mascheroni Construction of a Regular Pentagon\"\n    printfn \"\"\n\n    // We will follow the notation from \n    // https://www.cut-the-knot.org/pythagoras/MascheroniPentagon.shtml\n    // Read this article for detailed description of the algorithm\n\n    // Start with arbitrary points A and B (in plane XY)\n    let A = Point3d(0.0, 0.0, 0.0)\n    let B = Point3d(5.0, 0.0, 0.0)\n\n    // Draw a circle C1 with center in point A through point B\n    let C1 = Circle3d(A, A.DistanceTo(B), Vector3d(0.0, 0.0, 1.0))\n\n    // Draw a circle C2 with center in point B through point A\n    let C2 = Circle3d(B, A.DistanceTo(B), Vector3d(0.0, 0.0, 1.0))\n\n    // Intersection of C1 and C2 gives points C and D\n    let segment = C1.IntersectionWith C2 |> unbox<Segment3d>\n    let C = segment.P1\n    let D = segment.P2\n\n    // Draw a circle C3 with center in point C through point D\n    let C3 = Circle3d(C, C.DistanceTo(D), Vector3d(0.0, 0.0, 1.0))\n\n    // Intersection of C3 and C1 gives point E\n    let segment2 = C3.IntersectionWith C1 |> unbox<Segment3d> \n    // if E == D, choose another point of intersection\n    let E = if segment2.P1 = D then segment2.P2 else segment2.P1\n\n\n    // Intersection of C3 and C2 gives point F\n    let segment3 = C3.IntersectionWith C2 |> unbox<Segment3d> \n    // if F == D, choose another point of intersection\n    let F = if segment3.P1 = D then segment3.P2 else segment3.P1\n\n    // Draw a circle C4 with center in point A through point F\n    let C4 = Circle3d(A, A.DistanceTo(F), Vector3d(0.0, 0.0, 1.0))\n\n    // Draw a circle C5 with center in point B through point E\n    let C5 = Circle3d(B, B.DistanceTo(E), Vector3d(0.0, 0.0, 1.0))\n\n    // Intersection of C4 and C5 gives points G and H\n    let segment4 = C4.IntersectionWith C5 |> unbox<Segment3d> \n    // point G is closer to point D\n    let G, H = \n        if segment4.P1.DistanceTo D < segment4.P2.DistanceTo D then\n            segment4.P1, segment4.P2\n        else\n            segment4.P2, segment4.P1;\n\n    // Draw a circle C6 with center in point G through point C\n    let C6 = Circle3d(G, G.DistanceTo(C), Vector3d(0.0, 0.0, 1.0))\n\n    // Intersection of C6 and C3 gives points I and J\n    // we need to choose correct side for I and J\n    let segment5 = C6.IntersectionWith C3 |> unbox<Segment3d> \n    let I, J = \n        if segment5.P1.DistanceTo A < segment5.P1.DistanceTo B then\n            segment5.P1, segment5.P2\n        else\n            segment5.P1, segment5.P2\n\n    // Draw a circle C7 with center in point H through point C\n    let C7 = Circle3d(H, H.DistanceTo(C), Vector3d(0.0, 0.0, 1.0))\n\n    // Intersection of C7 and C3 gives points K and L\n    let segment6 = C7.IntersectionWith C3 |> unbox<Segment3d> \n    let K, L = \n        if segment6.P1.DistanceTo I < segment6.P1.DistanceTo J then\n            segment6.P1, segment6.P2\n        else\n            segment6.P2, segment6.P1\n\n    // Points DIKLJ define our pentagon\n    // Let's check if interion angles are equal 108 degrees (with accuracy 1e-8)\n    let angle1 = Vector3d(D, I).AngleToDeg(Vector3d(D, J))\n    let angle2 = Vector3d(I, D).AngleToDeg(Vector3d(I, K))\n    let angle3 = Vector3d(K, I).AngleToDeg(Vector3d(K, L))\n    let angle4 = Vector3d(L, K).AngleToDeg(Vector3d(L, J))\n    let angle5 = Vector3d(J, L).AngleToDeg(Vector3d(J, D))\n\n    let tolerance = 1e-8\n    if Math.Abs(angle1 - 108.0) < tolerance &&\n       Math.Abs(angle2 - 108.0) < tolerance &&\n       Math.Abs(angle3 - 108.0) < tolerance &&\n       Math.Abs(angle4 - 108.0) < tolerance &&\n       Math.Abs(angle5 - 108.0) < tolerance \n    then\n        printfn \"Your construction is correct!\"\n        printfn \"%A\" D\n        printfn \"%A\" I\n        printfn \"%A\" K\n        printfn \"%A\" L\n        printfn \"%A\" J\n\nsample1()\nsample2()\nsample3()"
  },
  {
    "path": "GeometRi.Example.FSharp/packages.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<packages>\n  <package id=\"FSharp.Core\" version=\"4.5.2\" targetFramework=\"net461\" />\n  <package id=\"System.ValueTuple\" version=\"4.4.0\" targetFramework=\"net461\" />\n</packages>"
  },
  {
    "path": "GeometRi.Tests/AABBTest.cs",
    "content": "﻿using System;\nusing static System.Math;\nusing Microsoft.VisualStudio.TestTools.UnitTesting;\nusing GeometRi;\n\nnamespace GeometRi_Tests\n{\n    [TestClass]\n    public class AABBTest\n    {\n        [TestMethod]\n        public void AABB_DistanceTo_AABB_1()\n        {\n            AABB box1 = new AABB(new Point3d(1, 1, 1), new Point3d(2, 2, 2));\n            AABB box2 = new AABB(new Point3d(3, 3, 3), new Point3d(4, 4, 4));\n            double dist = Sqrt(3);\n            Assert.IsTrue(GeometRi3D.AlmostEqual(dist, box1.DistanceTo(box2)));\n        }\n\n        [TestMethod]\n        public void AABB_DistanceTo_AABB_2()\n        {\n            AABB box1 = new AABB(new Point3d(1, 1, 1), new Point3d(2, 2, 2));\n            AABB box2 = new AABB(new Point3d(3, 1, 1), new Point3d(4, 2, 2));\n            double dist = 1;\n            Assert.IsTrue(GeometRi3D.AlmostEqual(dist, box1.DistanceTo(box2)));\n        }\n\n        [TestMethod]\n        public void AABB_IntersectionWith_AABB_01()\n        {\n            // Fully overlapping boxes\n            AABB box1 = new AABB(new Point3d(1, 1, 1), new Point3d(2, 2, 2));\n            AABB box2 = new AABB(new Point3d(0, 0, 0), new Point3d(4, 4, 4));\n\n            Assert.IsTrue(box1.IntersectionWith(box2) == box1);\n            Assert.IsTrue(box2.IntersectionWith(box1) == box1);\n            Assert.IsTrue(box1.Intersects(box2));\n            Assert.IsTrue(box2.Intersects(box1));\n\n        }\n\n        [TestMethod]\n        public void AABB_IntersectionWith_AABB_02()\n        {\n            // Partially overlapping boxes\n            AABB box1 = new AABB(new Point3d(1, 1, 1), new Point3d(3, 3, 3));\n            AABB box2 = new AABB(new Point3d(2, 2, 2), new Point3d(4, 4, 4));\n\n            AABB res = new AABB(new Point3d(2, 2, 2), new Point3d(3, 3, 3));\n\n            Assert.IsTrue(box1.IntersectionWith(box2) == res);\n            Assert.IsTrue(box2.IntersectionWith(box1) == res);\n            Assert.IsTrue(box1.Intersects(box2));\n            Assert.IsTrue(box2.Intersects(box1));\n        }\n\n        [TestMethod]\n        public void AABB_IntersectionWith_AABB_03()\n        {\n            // Non-overlapping boxes\n            AABB box1 = new AABB(new Point3d(1, 1, 1), new Point3d(3, 3, 3));\n            AABB box2 = new AABB(new Point3d(4, 4, 4), new Point3d(5, 5, 5));\n\n            Assert.IsTrue(box1.IntersectionWith(box2) == null);\n            Assert.IsTrue(box2.IntersectionWith(box1) == null);\n            Assert.IsFalse(box1.Intersects(box2));\n            Assert.IsFalse(box2.Intersects(box1));\n        }\n\n        [TestMethod]\n        public void PointInAABBTest()\n        {\n            Point3d p = new Point3d(1, 1, 1);\n            AABB box = new AABB(p, 8, 6, 10);\n\n            p = new Point3d(2, 2, 2);  // Point inside\n            Assert.IsTrue(p.BelongsTo(box));\n            Assert.IsTrue(p.IsInside(box));\n            Assert.IsFalse(p.IsOutside(box));\n            Assert.IsFalse(p.IsOnBoundary(box));\n\n            p = new Point3d(2, 4, 2);  // Point on side\n            Assert.IsTrue(p.BelongsTo(box));\n            Assert.IsFalse(p.IsInside(box));\n            Assert.IsFalse(p.IsOutside(box));\n            Assert.IsTrue(p.IsOnBoundary(box));\n\n            p = new Point3d(5, 4, 6);  // Point in corner\n            Assert.IsTrue(p.BelongsTo(box));\n            Assert.IsFalse(p.IsInside(box));\n            Assert.IsFalse(p.IsOutside(box));\n            Assert.IsTrue(p.IsOnBoundary(box));\n\n            p = new Point3d(5, -5, 6);  // Point outside\n            Assert.IsFalse(p.BelongsTo(box));\n            Assert.IsFalse(p.IsInside(box));\n            Assert.IsTrue(p.IsOutside(box));\n            Assert.IsFalse(p.IsOnBoundary(box));\n        }\n    }\n}\n"
  },
  {
    "path": "GeometRi.Tests/BoundingBoxTest.cs",
    "content": "﻿using System;\nusing static System.Math;\nusing Microsoft.VisualStudio.TestTools.UnitTesting;\nusing GeometRi;\n\nnamespace GeometRi_Tests\n{\n    [TestClass]\n    public class BoundingBoxTest\n    {\n        [TestMethod]\n        public void EllipsoidAABBTest()\n        {\n            Point3d p = new Point3d(0, 0, 0);\n            Vector3d v1 = new Vector3d(3, 0, 0);\n            Vector3d v2 = new Vector3d(0, 2, 0);\n            Vector3d v3 = new Vector3d(0, 0, 4);\n            Ellipsoid e = new Ellipsoid(p, v1, v2, v3);\n            Rotation r = new Rotation(new Vector3d(1, 2, 3), PI / 4);\n            e = e.Rotate(r, p);\n\n            Box3d b = e.BoundingBox();\n\n            Plane3d s = new Plane3d(b.P1, b.P2, b.P3);\n            Assert.IsTrue(e.IntersectionWith(s).GetType() == typeof(Point3d));\n\n            s = new Plane3d(b.P8, b.P7, b.P6);\n            Assert.IsTrue(e.IntersectionWith(s).GetType() == typeof(Point3d));\n\n            s = new Plane3d(b.P1, b.P2, b.P5);\n            Assert.IsTrue(e.IntersectionWith(s).GetType() == typeof(Point3d));\n\n            s = new Plane3d(b.P2, b.P3, b.P6);\n            Assert.IsTrue(e.IntersectionWith(s).GetType() == typeof(Point3d));\n\n            s = new Plane3d(b.P3, b.P4, b.P7);\n            Assert.IsTrue(e.IntersectionWith(s).GetType() == typeof(Point3d));\n\n            s = new Plane3d(b.P1, b.P4, b.P8);\n            Assert.IsTrue(e.IntersectionWith(s).GetType() == typeof(Point3d));\n        }\n\n        [TestMethod]\n        public void SphereAABBTest()\n        {\n            Point3d p = new Point3d(0, 0, 0);\n            Sphere e = new Sphere(p, 5);\n            Rotation r = new Rotation(new Vector3d(1, 2, 3), PI / 4);\n            Coord3d cs = new Coord3d(new Point3d(1, 2, 4), r.ToRotationMatrix.Transpose());\n\n            Box3d b = e.BoundingBox(cs);\n\n            Plane3d s = new Plane3d(b.P1, b.P2, b.P3);\n            Assert.IsTrue(e.IntersectionWith(s).GetType() == typeof(Point3d));\n\n            s = new Plane3d(b.P8, b.P7, b.P6);\n            Assert.IsTrue(e.IntersectionWith(s).GetType() == typeof(Point3d));\n\n            s = new Plane3d(b.P1, b.P2, b.P5);\n            Assert.IsTrue(e.IntersectionWith(s).GetType() == typeof(Point3d));\n\n            s = new Plane3d(b.P2, b.P3, b.P6);\n            Assert.IsTrue(e.IntersectionWith(s).GetType() == typeof(Point3d));\n\n            s = new Plane3d(b.P3, b.P4, b.P7);\n            Assert.IsTrue(e.IntersectionWith(s).GetType() == typeof(Point3d));\n\n            s = new Plane3d(b.P1, b.P4, b.P8);\n            Assert.IsTrue(e.IntersectionWith(s).GetType() == typeof(Point3d));\n        }\n\n        [TestMethod]\n        public void TriangleAABBTest()\n        {\n            Point3d p1 = new Point3d(1, 0, 2);\n            Point3d p2 = new Point3d(4, 2, 6);\n            Point3d p3 = new Point3d(0, 4, 0);\n            Triangle t = new Triangle(p1, p2, p3);\n\n            Box3d res = new Box3d(new Point3d(2, 2, 3), 4, 4, 6);\n\n            Assert.AreEqual(t.BoundingBox(), res);\n        }\n\n        [TestMethod]\n        public void CircleAABBTest()\n        {\n            Point3d p = new Point3d(1, 1, 1);\n            Vector3d v = new Vector3d(3, 4, 0);\n            Circle3d c = new Circle3d(p, 5, v);\n\n            Box3d res = new Box3d(p, 8, 6, 10);\n\n            Assert.AreEqual(c.BoundingBox(), res);\n        }\n    }\n}\n"
  },
  {
    "path": "GeometRi.Tests/Box3dTest.cs",
    "content": "﻿using System;\nusing static System.Math;\nusing Microsoft.VisualStudio.TestTools.UnitTesting;\nusing GeometRi;\nusing System.Collections.Generic;\n\nnamespace GeometRi_Tests\n{\n    [TestClass]\n    public class Box3dTest\n    {\n        [TestMethod]\n        public void DefaultBoxTest()\n        {\n            Rotation r = new Rotation(new Vector3d(2, 1, 5), PI / 3);\n            Coord3d coord1 = new Coord3d(new Point3d(2, 3, 1), r.ToRotationMatrix.Transpose());\n            Box3d b = new Box3d(coord1);\n\n            Assert.AreEqual(b.Center, coord1.Origin);\n            Assert.AreEqual(b.P1, new Point3d(-0.5, -0.5, -0.5, coord1));\n            Assert.AreEqual(b.P7, new Point3d(0.5, 0.5, 0.5, coord1));\n        }\n\n        [TestMethod]\n        public void CornerPointsTest()\n        {\n            Rotation r = new Rotation();\n            Point3d p = new Point3d(5, 5, 5);\n            Box3d b = new Box3d(p, 2, 2, 2, r);\n            Assert.AreEqual(b.P1, new Point3d(4, 4, 4));\n            Assert.AreEqual(b.P3, new Point3d(6, 6, 4));\n            Assert.AreEqual(b.P8, new Point3d(4, 6, 6));\n\n            r = Rotation.FromEulerAngles(PI / 2, -PI / 2, 0, \"zyz\");\n            b = new Box3d(p, 2, 2, 2, r);\n            Assert.AreEqual(b.P1, new Point3d(6, 4, 6));\n            Assert.AreEqual(b.P3, new Point3d(6, 6, 4));\n            Assert.AreEqual(b.P8, new Point3d(4, 4, 4));\n\n        }\n\n        [TestMethod]\n        public void BoxOrientationTest()\n        {\n            Rotation r = new Rotation(new Vector3d(0, 0, 1), PI / 4);\n            Coord3d coord1 = new Coord3d(new Point3d(2, 3, 1), r.ToRotationMatrix.Transpose());\n            Box3d b = new Box3d(coord1);\n\n            Assert.AreEqual(b.V1.Normalized, new Vector3d(1, 1, 0).Normalized);\n            Assert.AreEqual(b.V2.Normalized, new Vector3d(-1, 1, 0).Normalized);\n            Assert.AreEqual(b.V3.Normalized, new Vector3d(0, 0, 1).Normalized);\n        }\n\n\n        [TestMethod]\n        public void PointInAlignedBoxTest()\n        {\n            Point3d p = new Point3d(1, 1, 1);\n            Box3d box = new Box3d(p, 8, 6, 10);\n\n            p = new Point3d(2, 2, 2);  // Point inside\n            Assert.IsTrue(p.BelongsTo(box));\n            Assert.IsTrue(p.IsInside(box));\n            Assert.IsFalse(p.IsOutside(box));\n            Assert.IsFalse(p.IsOnBoundary(box));\n\n            p = new Point3d(2, 4, 2);  // Point on side\n            Assert.IsTrue(p.BelongsTo(box));\n            Assert.IsFalse(p.IsInside(box));\n            Assert.IsFalse(p.IsOutside(box));\n            Assert.IsTrue(p.IsOnBoundary(box));\n\n            p = new Point3d(5, 4, 6);  // Point in corner\n            Assert.IsTrue(p.BelongsTo(box));\n            Assert.IsFalse(p.IsInside(box));\n            Assert.IsFalse(p.IsOutside(box));\n            Assert.IsTrue(p.IsOnBoundary(box));\n\n            p = new Point3d(5, -5, 6);  // Point outside\n            Assert.IsFalse(p.BelongsTo(box));\n            Assert.IsFalse(p.IsInside(box));\n            Assert.IsTrue(p.IsOutside(box));\n            Assert.IsFalse(p.IsOnBoundary(box));\n        }\n\n        [TestMethod]\n        public void PointInAlignedBoxRelativeTest()\n        {\n            Point3d p = new Point3d(1, 1, 1);\n            Box3d box = new Box3d(p, 8, 6, 10);\n\n            double tol = GeometRi3D.Tolerance;\n            bool mode = GeometRi3D.UseAbsoluteTolerance;\n            GeometRi3D.Tolerance = 0.01;\n            GeometRi3D.UseAbsoluteTolerance = false;\n\n            p = new Point3d(2, 2, 2);  // Point inside\n            Assert.IsTrue(p.BelongsTo(box));\n            Assert.IsTrue(p.IsInside(box));\n            Assert.IsFalse(p.IsOutside(box));\n            Assert.IsFalse(p.IsOnBoundary(box));\n\n            p = new Point3d(2, 4.1, 2);  // Point on side\n            Assert.IsTrue(p.BelongsTo(box));\n            Assert.IsFalse(p.IsInside(box));\n            Assert.IsFalse(p.IsOutside(box));\n            Assert.IsTrue(p.IsOnBoundary(box));\n\n            p = new Point3d(5.1, 4, 6);  // Point in corner\n            Assert.IsTrue(p.BelongsTo(box));\n            Assert.IsFalse(p.IsInside(box));\n            Assert.IsFalse(p.IsOutside(box));\n            Assert.IsTrue(p.IsOnBoundary(box));\n\n            p = new Point3d(2, 4.2, 2);  // Point outside\n            Assert.IsFalse(p.BelongsTo(box));\n            Assert.IsFalse(p.IsInside(box));\n            Assert.IsTrue(p.IsOutside(box));\n            Assert.IsFalse(p.IsOnBoundary(box));\n\n            // Resore initial state\n            GeometRi3D.UseAbsoluteTolerance = mode;\n            GeometRi3D.Tolerance = tol;\n        }\n\n        [TestMethod]\n        public void ClosestPointTest()\n        {\n            Rotation r = new Rotation(new Vector3d(2, 1, 5), PI / 3);\n            Box3d b = new Box3d(new Point3d(1, 1, 1), 2, 2, 2);\n            Point3d p0 = new Point3d(1, 2, 2);\n            Point3d p1 = new Point3d(-1, -1, -1);\n            Point3d p3 = new Point3d(3, 3, -1);\n            Point3d p6 = new Point3d(3, -1, 3);\n\n            b = b.Rotate(r, p0);\n            p1 = p1.Rotate(r, p0);\n            p3 = p3.Rotate(r, p0);\n            p6 = p6.Rotate(r, p0);\n\n            Assert.AreEqual(p0, b.ClosestPoint(p0));\n            Assert.AreEqual(b.P1, b.ClosestPoint(p1));\n            Assert.AreEqual(b.P3, b.ClosestPoint(p3));\n            Assert.AreEqual(b.P6, b.ClosestPoint(p6));\n        }\n\n        [TestMethod]\n        public void DistanceToPointTest()\n        {\n            Box3d b = new Box3d();\n            Point3d p1 = new Point3d(0.3, 0.4, 0.2); // Point inside box\n            Point3d p2 = new Point3d(0.3, 0.4, 0.5); // Point on boundary\n            Point3d p3 = new Point3d(0.3, 0.4, 1.0); // Point outside box\n\n            Assert.IsTrue(GeometRi3D.AlmostEqual(b.DistanceTo(p1), 0.0));\n            Assert.IsTrue(GeometRi3D.AlmostEqual(b.DistanceTo(p2), 0.0));\n            Assert.IsTrue(GeometRi3D.AlmostEqual(b.DistanceTo(p3), 0.5));\n        }\n\n        [TestMethod]\n        public void LineIntersectionWithBoxTest()\n        {\n            Rotation rot = new Rotation();\n            Point3d p = new Point3d(0, 0, 0);\n            Box3d b = new Box3d(p, 2, 2, 2, rot);\n\n            Line3d l = new Line3d(new Point3d(1, 1, 1), new Vector3d(1, 1, 1));\n            Segment3d s = (Segment3d)b.IntersectionWith(l);\n            Assert.AreEqual(s, new Segment3d(new Point3d(-1, -1, -1), new Point3d(1, 1, 1)));\n\n            l = new Line3d(new Point3d(1, -1, -1), new Vector3d(-1, 1, 1));\n            s = (Segment3d)b.IntersectionWith(l);\n            Assert.AreEqual(s, new Segment3d(new Point3d(1, -1, -1), new Point3d(-1, 1, 1)));\n\n            l = new Line3d(new Point3d(0, 0, 0), new Vector3d(1, 0, 0));\n            s = (Segment3d)b.IntersectionWith(l);\n            Assert.AreEqual(s, new Segment3d(new Point3d(-1, 0, 0), new Point3d(1, 0, 0)));\n\n            l = new Line3d(new Point3d(0, 0, 0), new Vector3d(0, 1, 0));\n            s = (Segment3d)b.IntersectionWith(l);\n            Assert.AreEqual(s, new Segment3d(new Point3d(0, -1, 0), new Point3d(0, 1, 0)));\n\n            l = new Line3d(new Point3d(0, 0, 0), new Vector3d(0, 0, 1));\n            s = (Segment3d)b.IntersectionWith(l);\n            Assert.AreEqual(s, new Segment3d(new Point3d(0, 0, -1), new Point3d(0, 0, 1)));\n\n            // Intersection is point\n            l = new Line3d(new Point3d(-1, -1, 1), new Vector3d(1, 1, 1));\n            Assert.AreEqual((Point3d)b.IntersectionWith(l), new Point3d(-1, -1, 1));\n        }\n\n        [TestMethod]\n        public void RayIntersectionWithBoxTest()\n        {\n            Rotation rot = new Rotation();\n            Point3d p = new Point3d(0, 0, 0);\n            Box3d b = new Box3d(p, 2, 2, 2, rot);\n\n            Ray3d r = new Ray3d(new Point3d(-1, -1, -1), new Vector3d(1, 1, 1));\n            Segment3d s = (Segment3d)b.IntersectionWith(r);\n            Assert.AreEqual(s, new Segment3d(new Point3d(-1, -1, -1), new Point3d(1, 1, 1)));\n\n            r = new Ray3d(new Point3d(0, 0, 0), new Vector3d(1, 1, 1));\n            s = (Segment3d)b.IntersectionWith(r);\n            Assert.AreEqual(s, new Segment3d(new Point3d(0, 0, 0), new Point3d(1, 1, 1)));\n\n            r = new Ray3d(new Point3d(1, -1, -1), new Vector3d(-1, 1, 1));\n            s = (Segment3d)b.IntersectionWith(r);\n            Assert.AreEqual(s, new Segment3d(new Point3d(1, -1, -1), new Point3d(-1, 1, 1)));\n\n            r = new Ray3d(new Point3d(0, 0, 0), new Vector3d(1, 0, 0));\n            s = (Segment3d)b.IntersectionWith(r);\n            Assert.AreEqual(s, new Segment3d(new Point3d(0, 0, 0), new Point3d(1, 0, 0)));\n\n            r = new Ray3d(new Point3d(0, 0, 0), new Vector3d(0, -1, 0));\n            s = (Segment3d)b.IntersectionWith(r);\n            Assert.AreEqual(s, new Segment3d(new Point3d(0, 0, 0), new Point3d(0, -1, 0)));\n\n            r = new Ray3d(new Point3d(0, 0, 0), new Vector3d(0, 0, 1));\n            s = (Segment3d)b.IntersectionWith(r);\n            Assert.AreEqual(s, new Segment3d(new Point3d(0, 0, 0), new Point3d(0, 0, 1)));\n\n            // Intersection is point\n            r = new Ray3d(new Point3d(-1, -1, 1), new Vector3d(1, 1, 1));\n            Assert.AreEqual((Point3d)b.IntersectionWith(r), new Point3d(-1, -1, 1));\n        }\n\n        [TestMethod]\n        public void SegmentIntersectionWithBoxTest()\n        {\n            Rotation rot = new Rotation();\n            Point3d p = new Point3d(0, 0, 0);\n            Box3d b = new Box3d(p, 2, 2, 2, rot);\n\n            Segment3d s = new Segment3d(new Point3d(-1, -1, -1), new Point3d(1, 1, 1));\n            Assert.AreEqual((Segment3d)b.IntersectionWith(s), new Segment3d(new Point3d(-1, -1, -1), new Point3d(1, 1, 1)));\n\n            s = new Segment3d(new Point3d(0, 0, 0), new Point3d(1, 1, 1));\n            Assert.AreEqual((Segment3d)b.IntersectionWith(s), new Segment3d(new Point3d(0, 0, 0), new Point3d(1, 1, 1)));\n\n            s = new Segment3d(new Point3d(1, -1, -1), new Point3d(-1, 1, 1));\n            Assert.AreEqual((Segment3d)b.IntersectionWith(s), new Segment3d(new Point3d(1, -1, -1), new Point3d(-1, 1, 1)));\n\n            s = new Segment3d(new Point3d(0, 0, 0), new Point3d(1, 0, 0));\n            Assert.AreEqual((Segment3d)b.IntersectionWith(s), new Segment3d(new Point3d(0, 0, 0), new Point3d(1, 0, 0)));\n\n            s = new Segment3d(new Point3d(0, 0, 0), new Point3d(0, -1, 0));\n            Assert.AreEqual((Segment3d)b.IntersectionWith(s), new Segment3d(new Point3d(0, 0, 0), new Point3d(0, -1, 0)));\n\n            s = new Segment3d(new Point3d(0, 0, 0), new Point3d(0, 0, 1));\n            Assert.AreEqual((Segment3d)b.IntersectionWith(s), new Segment3d(new Point3d(0, 0, 0), new Point3d(0, 0, 1)));\n\n            // Intersection is point\n            s = new Segment3d(new Point3d(-1, -1, 1), new Point3d(0, 0, 2));\n            Assert.AreEqual((Point3d)b.IntersectionWith(s), new Point3d(-1, -1, 1));\n        }\n\n        [TestMethod]\n        public void SegmentIntersectionWithBoxRelativeTest()\n        {\n\n            double tol = GeometRi3D.Tolerance;\n            bool mode = GeometRi3D.UseAbsoluteTolerance;\n            GeometRi3D.Tolerance = 0.01;\n            GeometRi3D.UseAbsoluteTolerance = false;\n\n            Rotation rot = new Rotation();\n            Point3d p = new Point3d(0, 0, 0);\n            Box3d b = new Box3d(p, 2, 2, 2, rot);\n\n            // Segment aligned with X-axis\n            Segment3d s = new Segment3d(new Point3d(-2, 0, 0), new Point3d(-1.01, 0, 0));\n            Assert.AreEqual((Point3d)b.IntersectionWith(s), new Point3d(-1, 0, 0));\n\n            s = new Segment3d(new Point3d(1.01, 0, 0), new Point3d(2, 0, 0));\n            Assert.AreEqual((Point3d)b.IntersectionWith(s), new Point3d(1, 0, 0));\n\n            s = new Segment3d(new Point3d(-0.5, 0, 0), new Point3d(0.5, 0, 0));\n            Assert.AreEqual((Segment3d)b.IntersectionWith(s), s);\n\n            s = new Segment3d(new Point3d(-1.5, 0, 0), new Point3d(1.5, 0, 0));\n            Assert.AreEqual((Segment3d)b.IntersectionWith(s), new Segment3d(new Point3d(-1, 0, 0), new Point3d(1, 0, 0)));\n\n            // Segment aligned with Y-axis\n            s = new Segment3d(new Point3d(0, -2, 0), new Point3d(0, -1.01, 0));\n            Assert.AreEqual((Point3d)b.IntersectionWith(s), new Point3d(0, -1, 0));\n\n            s = new Segment3d(new Point3d(0, 1.01, 0), new Point3d(0, 2, 0));\n            Assert.AreEqual((Point3d)b.IntersectionWith(s), new Point3d(0, 1, 0));\n\n            s = new Segment3d(new Point3d(0, -0.5, 0), new Point3d(0, 0.5, 0));\n            Assert.AreEqual((Segment3d)b.IntersectionWith(s), s);\n\n            s = new Segment3d(new Point3d(0, -1.5, 0), new Point3d(0, 1.5, 0));\n            Assert.AreEqual((Segment3d)b.IntersectionWith(s), new Segment3d(new Point3d(0, -1, 0), new Point3d(0, 1, 0)));\n\n            // Segment aligned with Z-axis\n            s = new Segment3d(new Point3d(0, 0, -2), new Point3d(0, 0, -1.01));\n            Assert.AreEqual((Point3d)b.IntersectionWith(s), new Point3d(0, 0, -1));\n\n            s = new Segment3d(new Point3d(0, 0, 1.01), new Point3d(0, 0, 2));\n            Assert.AreEqual((Point3d)b.IntersectionWith(s), new Point3d(0, 0, 1));\n\n            s = new Segment3d(new Point3d(0, 0, -0.5), new Point3d(0, 0, 0.5));\n            Assert.AreEqual((Segment3d)b.IntersectionWith(s), s);\n\n            s = new Segment3d(new Point3d(0, 0, -1.5), new Point3d(0, 0, 1.5));\n            Assert.AreEqual((Segment3d)b.IntersectionWith(s), new Segment3d(new Point3d(0, 0, -1), new Point3d(0, 0, 1)));\n\n            // Segment crossing corner\n            s = new Segment3d(new Point3d(2.01, 0, 1), new Point3d(0.01, 2, 1));\n            Assert.AreEqual((Point3d)b.IntersectionWith(s), new Point3d(1, 1, 1));\n\n            // Resore initial state\n            GeometRi3D.UseAbsoluteTolerance = mode;\n            GeometRi3D.Tolerance = tol;\n        }\n\n        [TestMethod]\n        public void BoxRotationTest()\n        {\n            Rotation r1 = new Rotation(new Vector3d(0, 0, 1), PI / 2);\n            Rotation r2 = new Rotation(new Vector3d(1, 0, 0), PI / 2);\n            Box3d b = new Box3d();\n\n            b = b.Rotate(r1, new Point3d(-5, 0, 0));\n            b = b.Rotate(r2, new Point3d(-5, 0, 0));\n\n            Assert.AreEqual(b.V1.Normalized, new Vector3d(0, 0, 1));\n            Assert.AreEqual(b.V2.Normalized, new Vector3d(-1, 0, 0));\n            Assert.AreEqual(b.V3.Normalized, new Vector3d(0, -1, 0));\n            Assert.AreEqual(b.Center, new Point3d(-5, 0, 5));\n        }\n\n        [TestMethod]\n        public void BoxReflectInPointTest()\n        {\n\n            Box3d b = new Box3d();\n            List<Point3d> original_points = b.ListOfPoints;\n\n            Point3d p = new Point3d(-4.1, 7.876, -8);\n            Box3d reflected_box = b.ReflectIn(p);\n            List<Point3d> reflected_points = reflected_box.ListOfPoints;\n\n            foreach (Point3d op in original_points)\n            {\n                Point3d reflected_p = op.ReflectIn(p);\n                foreach (Point3d rp in reflected_points)\n                {\n                    if (reflected_p == rp)\n                    {\n                        reflected_points.Remove(rp);\n                        break;\n                    }\n                }\n            }\n\n            Assert.IsTrue(reflected_points.Count == 0);\n\n        }\n\n        [TestMethod]\n        public void BoxReflectInLineTest()\n        {\n\n            Box3d b = new Box3d();\n            List < Point3d > original_points = b.ListOfPoints;\n\n            Line3d l = new Line3d(new Point3d(-4.1, 7.876, -8), new Vector3d(1.25, -8, -22));\n            Box3d reflected_box = b.ReflectIn(l);\n            List  < Point3d > reflected_points = reflected_box.ListOfPoints;\n\n            foreach (Point3d op in original_points)\n            {\n                Point3d reflected_p = op.ReflectIn(l);\n                foreach (Point3d rp in reflected_points)\n                {\n                    if (reflected_p == rp)\n                    {\n                        reflected_points.Remove(rp);\n                        break;\n                    }\n                }\n            }\n\n            Assert.IsTrue(reflected_points.Count == 0);\n\n        }\n\n        [TestMethod]\n        public void BoxReflectInPlaneTest()\n        {\n\n            Box3d b = new Box3d();\n            List<Point3d> original_points = b.ListOfPoints;\n\n            Plane3d s = new Plane3d(new Point3d(-4.1, 7.876, -8), new Vector3d(1.25, -8, -22));\n            Box3d reflected_box = b.ReflectIn(s);\n            List<Point3d> reflected_points = reflected_box.ListOfPoints;\n\n            foreach (Point3d op in original_points)\n            {\n                Point3d reflected_p = op.ReflectIn(s);\n                foreach (Point3d rp in reflected_points)\n                {\n                    if (reflected_p == rp)\n                    {\n                        reflected_points.Remove(rp);\n                        break;\n                    }\n                }\n            }\n\n            Assert.IsTrue(reflected_points.Count == 0);\n\n        }\n\n        [TestMethod()]\n        public void BoxDistanceToCircleTest()\n        {\n            Box3d box = new Box3d();\n            Circle3d c = new Circle3d(new Point3d(-1.3195, -1.0435, -0.70047), 0.35, new Vector3d(0.83694, -0.13208, -0.53112));\n\n            double dist = box.DistanceTo(c);\n            Assert.IsTrue(dist > 0);\n\n        }\n\n        [TestMethod()]\n        public void BoxIntersectsCircleTest()\n        {\n            Box3d box = new Box3d();\n            Circle3d c = new Circle3d(new Point3d(), 1, new Vector3d(0, 0, 1));\n            Assert.IsTrue(c.Intersects(box));\n\n            c = new Circle3d(new Point3d(1.5, 0, 0), 1, new Vector3d(0, 0, 1));\n            Assert.IsTrue(c.Intersects(box));\n\n            c = new Circle3d(new Point3d(0.5, 0.5, 0.5), 1, new Vector3d(1, 1, 1));\n            Assert.IsTrue(c.Intersects(box));\n\n            c = new Circle3d(new Point3d(0.6, 0.6, 0.6), 1, new Vector3d(1, 1, 1));\n            Assert.IsFalse(c.Intersects(box));\n\n        }\n\n        [TestMethod()]\n        public void BoxIntersectsCircleTest2()\n        {\n            Box3d box = new Box3d(new Point3d(0.5, 0.5, 0.5), 1, 1, 1);\n            Circle3d c = new Circle3d(new Point3d(0.957494668177094, 1.08987119472114, -0.11622424522239),\n                                      0.154926580712558, \n                                      new Vector3d(0.362303959251271, 0.267138656415756, 0.892957322249635));\n            Assert.IsFalse(c.Intersects(box));\n\n\n        }\n\n        [TestMethod()]\n        public void BoxIntersectsTriangleTest()\n        {\n            Box3d box = new Box3d();\n            \n            // Triangle is inside box\n            Triangle t = new Triangle(new Point3d(0, 0, 0), new Point3d(0.2, -0.1, 0), new Point3d(0, -0.2, -0.1));\n            Assert.IsTrue(box.Intersects(t));\n\n            // Triangle is outside of box\n            t = new Triangle(new Point3d(1, 1, 1), new Point3d(2, 1, 1), new Point3d(1, 2, 1));\n            Assert.IsFalse(box.Intersects(t));\n\n            // Triangle touches box\n            t = new Triangle(new Point3d(0.5, 0, 0), new Point3d(0.7, -0.1, 0), new Point3d(0.8, -0.2, -0.1));\n            Assert.IsTrue(box.Intersects(t));\n\n            // Triangle intersects box\n            t = new Triangle(new Point3d(-1, -1, 0), new Point3d(0.7, 0.9, 0.1), new Point3d(0.8, -2, -0.1));\n            Assert.IsTrue(box.Intersects(t));\n        }\n\n        [TestMethod()]\n        public void BoxIntersectsBoxTest_01()\n        {\n            //non intersecting boxes\n            Box3d box1 = new Box3d(new Point3d(0.5, 0.5, 0.5), 1, 1, 1);\n            Box3d box2 = new Box3d(new Point3d(2.5, 0.5, 0.5), 1, 1, 1);\n            Assert.IsFalse(box1.Intersects(box2));\n        }\n\n        [TestMethod()]\n        public void BoxIntersectsBoxTest_02()\n        {\n            //touching boxes\n            Box3d box1 = new Box3d(new Point3d(0.5, 0.5, 0.5), 1, 1, 1);\n            Box3d box2 = new Box3d(new Point3d(1.5, 0.5, 0.5), 1, 1, 1);\n            Assert.IsTrue(box1.Intersects(box2));\n        }\n\n        [TestMethod()]\n        public void BoxIntersectsBoxTest_03()\n        {\n            //intersecting boxes\n            Box3d box1 = new Box3d(new Point3d(0.5, 0.5, 0.5), 1, 1, 1);\n            Box3d box2 = new Box3d(new Point3d(1.4, 0.5, 0.5), 1, 1, 1);\n            Assert.IsTrue(box1.Intersects(box2));\n        }\n\n\n    }\n\n\n}\n"
  },
  {
    "path": "GeometRi.Tests/CircleTest.cs",
    "content": "﻿using System;\nusing static System.Math;\nusing Microsoft.VisualStudio.TestTools.UnitTesting;\nusing GeometRi;\n\nnamespace GeometRi_Tests\n{\n    [TestClass]\n    public class CircleTest\n    {\n        //===============================================================\n        // Circle3d tests\n        //===============================================================\n\n        [TestMethod()]\n        public void CircleBy3PointsTest()\n        {\n            Point3d p1 = new Point3d(-3, 0, 4);\n            Point3d p2 = new Point3d(4, 0, 5);\n            Point3d p3 = new Point3d(1, 0, -4);\n\n            Circle3d c = new Circle3d(p1, p2, p3);\n\n            Assert.IsTrue(c.Center == new Point3d(1, 0, 1));\n            Assert.IsTrue(Abs(c.R - 5) <= GeometRi3D.Tolerance);\n        }\n\n        [TestMethod()]\n        public void CircleIntersectionWithLineTest()\n        {\n            // parallel obecjts\n            Circle3d c = new Circle3d(new Point3d(0, 0, 0), 5, new Vector3d(0, 0, 1));\n            Line3d l = new Line3d(new Point3d(0, 0, 1), new Vector3d(1, 0, 0));\n            Assert.AreEqual(c.IntersectionWith(l), null);\n\n            // nonintersecting objects\n            c = new Circle3d(new Point3d(0, 0, 0), 5, new Vector3d(0, 0, 1));\n            l = new Line3d(new Point3d(10, 0, 0), new Vector3d(1, 1, 0));\n            Assert.AreEqual(c.IntersectionWith(l), null);\n\n            // intersection in one point (touching line)\n            c = new Circle3d(new Point3d(0, 0, 0), 5, new Vector3d(0, 0, 1));\n            l = new Line3d(new Point3d(5, 0, 0), new Vector3d(0, 1, 0));\n            Assert.AreEqual(c.IntersectionWith(l), new Point3d(5, 0, 0));\n\n            // intersection in one point (crossing line)\n            c = new Circle3d(new Point3d(0, 0, 0), 5, new Vector3d(0, 0, 1));\n            l = new Line3d(new Point3d(1, 1, 0), new Vector3d(0, 0, 1));\n            Assert.AreEqual(c.IntersectionWith(l), new Point3d(1, 1, 0));\n\n            // intersection in two points\n            c = new Circle3d(new Point3d(0, 0, 0), 5, new Vector3d(0, 0, 1));\n            l = new Line3d(new Point3d(0, -4, 0), new Vector3d(1, 0, 0));\n            Assert.AreEqual(c.IntersectionWith(l), new Segment3d(new Point3d(-3, -4, 0), new Point3d(3, -4, 0)));\n\n        }\n\n        [TestMethod()]\n        public void CircleIntersectionWithRayTest()\n        {\n            // intersection in one point (crossing ray)\n            Circle3d c = new Circle3d(new Point3d(0, 0, 0), 5, new Vector3d(0, 0, 1));\n            Ray3d r = new Ray3d(new Point3d(0, 0, 0), new Vector3d(1, 0, 0));\n            Assert.AreEqual(c.IntersectionWith(r), new Segment3d(new Point3d(5, 0, 0), new Point3d(0, 0, 0)));\n\n            // intersection in one point (touching line)\n            r = new Ray3d(new Point3d(5, 0, 0), new Vector3d(1, 0, 0));\n            Assert.AreEqual(c.IntersectionWith(r), new Point3d(5, 0, 0));\n\n        }\n\n        [TestMethod()]\n        public void CircleIntersectionWithPlaneTest()\n        {\n            // parallel obecjts\n            Circle3d c = new Circle3d(new Point3d(5, 6, 1), 5, new Vector3d(0, 0, 1));\n            Plane3d s = new Plane3d(new Point3d(0, 0, 0), new Vector3d(0, 0, 1));\n            Assert.AreEqual(c.IntersectionWith(s), null);\n\n            // coplanar objects\n            s = new Plane3d(new Point3d(0, 0, 1), new Vector3d(0, 0, 1));\n            Assert.AreEqual(c.IntersectionWith(s), c);\n\n            // nonintersecting objects\n            c = new Circle3d(new Point3d(5, 6, 10), 5, new Vector3d(0, 0, 1));\n            s = new Plane3d(new Point3d(0, 0, 1), new Vector3d(0, 0, 1));\n            Assert.AreEqual(c.IntersectionWith(s), null);\n\n            // intersection in one point\n            c = new Circle3d(new Point3d(0, 0, 3), 5, new Vector3d(3, 0, 4));\n            s = new Plane3d(new Point3d(5, 5, 0), new Vector3d(0, 0, 1));\n            Assert.AreEqual(c.IntersectionWith(s), new Point3d(4, 0, 0));\n\n            // intersection in two points\n            c = new Circle3d(new Point3d(0, 0, 3), 5, new Vector3d(3, 0, 0));\n            s = new Plane3d(new Point3d(5, 5, 0), new Vector3d(0, 0, 1));\n            Assert.AreEqual(c.IntersectionWith(s), new Segment3d(new Point3d(0, 4, 0), new Point3d(0, -4, 0)));\n\n        }\n\n        [TestMethod()]\n        public void CircleIntersectionWithCircle2DTest()\n        {\n            // parallel obecjts\n            Circle3d c1 = new Circle3d(new Point3d(0, 0, 0), 5, new Vector3d(0, 0, 1));\n            Circle3d c2 = new Circle3d(new Point3d(5, 0, 1), 5, new Vector3d(0, 0, 1));\n            Assert.AreEqual(c1.IntersectionWith(c2), null);\n            Assert.IsFalse(c1.Intersects(c2));\n\n            // Coincided circles\n            c2 = new Circle3d(new Point3d(0, 0, 0), 5, new Vector3d(0, 0, 1));\n            Assert.AreEqual(c1.IntersectionWith(c2), c1);\n            Assert.IsTrue(c1.Intersects(c2));\n\n            // Separated circles\n            c2 = new Circle3d(new Point3d(10, 0, 0), 2, new Vector3d(0, 0, 1));\n            Assert.AreEqual(c1.IntersectionWith(c2), null);\n            Assert.IsFalse(c1.Intersects(c2));\n\n            // Outer tangency\n            c2 = new Circle3d(new Point3d(10, 0, 0), 5, new Vector3d(0, 0, 1));\n            Assert.AreEqual(c1.IntersectionWith(c2), new Point3d(5, 0, 0));\n            Assert.IsTrue(c1.Intersects(c2));\n\n            // Inner tangency 1\n            c2 = new Circle3d(new Point3d(3, 0, 0), 2, new Vector3d(0, 0, 1));\n            Assert.AreEqual(c1.IntersectionWith(c2), new Point3d(5, 0, 0));\n            Assert.IsTrue(c1.Intersects(c2));\n\n            // Inner tangency 2\n            c2 = new Circle3d(new Point3d(-2, 0, 0), 7, new Vector3d(0, 0, 1));\n            Assert.AreEqual(c1.IntersectionWith(c2), new Point3d(5, 0, 0));\n            Assert.IsTrue(c1.Intersects(c2));\n\n            // Intersection\n            c2 = new Circle3d(new Point3d(6, 0, 0), 5, new Vector3d(0, 0, 1));\n            Segment3d s = new Segment3d(new Point3d(3, 4, 0), new Point3d(3, -4, 0));\n            Assert.AreEqual(c1.IntersectionWith(c2), s);\n            Assert.IsTrue(c1.Intersects(c2));\n\n        }\n\n        [TestMethod()]\n        public void CircleIntersectionWithCircle3DTest()\n        {\n            // Touching circles\n            Circle3d c1 = new Circle3d(new Point3d(0, 0, 0), 5, new Vector3d(0, 0, 1));\n            Circle3d c2 = new Circle3d(new Point3d(5, 0, 0), 5, new Vector3d(1, 0, 0));\n            Assert.AreEqual(c1.IntersectionWith(c2), new Point3d(5, 0, 0));\n            Assert.IsTrue(c1.Intersects(c2));\n\n            // Touching circles\n            c1 = new Circle3d(new Point3d(0, 0, 0), 5, new Vector3d(0, 0, 1));\n            c2 = new Circle3d(new Point3d(5, 0, 5), 5, new Vector3d(1, 0, 0));\n            Assert.AreEqual(c1.IntersectionWith(c2), new Point3d(5, 0, 0));\n            Assert.IsTrue(c1.Intersects(c2));\n\n            // Non touching circles\n            c1 = new Circle3d(new Point3d(0, 0, 0), 5, new Vector3d(0, 0, 1));\n            c2 = new Circle3d(new Point3d(6, 0, 5), 5, new Vector3d(1, 0, 0));\n            Assert.IsNull(c1.IntersectionWith(c2));\n            Assert.IsFalse(c1.Intersects(c2));\n\n            // Touching circles\n            c2 = new Circle3d(new Point3d(10, 0, 0), 5, new Vector3d(0, 1, 0));\n            Assert.AreEqual(c1.IntersectionWith(c2), new Point3d(5, 0, 0));\n            Assert.IsTrue(c1.Intersects(c2));\n\n            // Intersecting circles\n            c2 = new Circle3d(new Point3d(0, 0, 0), 5, new Vector3d(0, 1, 0));\n            Segment3d s = new Segment3d(new Point3d(-5, 0, 0), new Point3d(5, 0, 0));\n            Assert.AreEqual(c1.IntersectionWith(c2), s);\n            Assert.IsTrue(c1.Intersects(c2));\n\n            // Intersecting circles\n            c2 = new Circle3d(new Point3d(5, 0, 0), 5, new Vector3d(0, 1, 0));\n            s = new Segment3d(new Point3d(0, 0, 0), new Point3d(5, 0, 0));\n            Assert.AreEqual(c1.IntersectionWith(c2), s);\n            Assert.IsTrue(c1.Intersects(c2));\n\n            // Intersecting circles\n            c2 = new Circle3d(new Point3d(0, 0, 4), 5, new Vector3d(0, 1, 0));\n            s = new Segment3d(new Point3d(-3, 0, 0), new Point3d(3, 0, 0));\n            Assert.AreEqual(c1.IntersectionWith(c2), s);\n            Assert.IsTrue(c1.Intersects(c2));\n\n        }\n\n        [TestMethod()]\n        public void CircleIntersectionWithCircle3DTest_2()\n        {\n            double tol = GeometRi3D.Tolerance;\n            bool mode = GeometRi3D.UseAbsoluteTolerance;\n            GeometRi3D.Tolerance = 0.01;\n            GeometRi3D.UseAbsoluteTolerance = true;\n\n            Circle3d c1 = new Circle3d(new Point3d(-0.28776, -0.29482, -0.16311), 0.2, new Vector3d(-0.44759, -0.3224, -0.8341));\n            Circle3d c2 = new Circle3d(new Point3d(-0.35134, -0.27228, -0.12871), 0.2, new Vector3d(0.84394, -0.416, -0.33868));\n            Assert.IsTrue(c1.IntersectionWith(c2) != null);\n            Assert.IsTrue(c2.IntersectionWith(c1) != null);\n            Assert.IsTrue(c1.Intersects(c2));\n            Assert.IsTrue(c2.Intersects(c1));\n\n            // Restore initial state\n            GeometRi3D.UseAbsoluteTolerance = mode;\n            GeometRi3D.Tolerance = tol;\n        }\n\n        [TestMethod()]\n        public void CircleIntersectionWithCircle3DTest_3()\n        {\n            double tol = GeometRi3D.Tolerance;\n            bool mode = GeometRi3D.UseAbsoluteTolerance;\n            GeometRi3D.Tolerance = 0.04;\n            GeometRi3D.UseAbsoluteTolerance = true;\n\n            Circle3d c1 = new Circle3d(new Point3d(0.36335, -0.46836, -0.11003), 0.25, new Vector3d(0.89975, -0.12088, -0.41932));\n            Circle3d c2 = new Circle3d(new Point3d(0.18967, -0.14709, 0.081927), 0.25, new Vector3d(0.90756, -0.16092, -0.38787));\n            Assert.IsTrue(c1.IntersectionWith(c2) == null);\n            Assert.IsTrue(c2.IntersectionWith(c1) == null);\n            Assert.IsFalse(c1.Intersects(c2));\n            Assert.IsFalse(c2.Intersects(c1));\n\n            // Restore initial state\n            GeometRi3D.UseAbsoluteTolerance = mode;\n            GeometRi3D.Tolerance = tol;\n        }\n\n        [TestMethod()]\n        public void CircleIntersectionWithCircle3DTest_4()\n        {\n            double tol = GeometRi3D.Tolerance;\n            bool mode = GeometRi3D.UseAbsoluteTolerance;\n            GeometRi3D.Tolerance = 0.03;\n            GeometRi3D.UseAbsoluteTolerance = true;\n\n            Circle3d c1 = new Circle3d(new Point3d(0.21512, -0.00082439, 0.17926), 0.3, new Vector3d(0.62821, -0.68096, 0.37636));\n            Circle3d c2 = new Circle3d(new Point3d(-0.038202, -0.090672, -0.078966), 0.3, new Vector3d(-0.060788, -0.026431, 0.9978));\n            Assert.IsTrue(c1.IntersectionWith(c2) != null);\n            Assert.IsTrue(c2.IntersectionWith(c1) != null);\n            Assert.IsTrue(c1.Intersects(c2));\n            Assert.IsTrue(c2.Intersects(c1));\n\n            // Restore initial state\n            GeometRi3D.UseAbsoluteTolerance = mode;\n            GeometRi3D.Tolerance = tol;\n        }\n\n        [TestMethod()]\n        public void CircleIntersectionWithCircle3DTest_5()\n        {\n            double tol = GeometRi3D.Tolerance;\n            bool mode = GeometRi3D.UseAbsoluteTolerance;\n            GeometRi3D.Tolerance = 0.01;\n            GeometRi3D.UseAbsoluteTolerance = true;\n\n            Circle3d c1 = new Circle3d(new Point3d(-0.15988, 0.3074, 0.11761), 0.1, new Vector3d(-0.14315, -0.33678, 0.93064));\n            Circle3d c2 = new Circle3d(new Point3d(-0.13031, 0.2539, 0.11499), 0.1, new Vector3d(0.70155, 0.62669, -0.33924));\n            Assert.IsTrue(c1.IntersectionWith(c2) != null);\n            Assert.IsTrue(c2.IntersectionWith(c1) != null);\n            Assert.IsTrue(c1.Intersects(c2));\n            Assert.IsTrue(c2.Intersects(c1));\n\n            // Restore initial state\n            GeometRi3D.UseAbsoluteTolerance = mode;\n            GeometRi3D.Tolerance = tol;\n        }\n\n        [TestMethod()]\n        public void CircleIntersectionWithCircle3DTest_6()\n        {\n\n            Circle3d c1 = new Circle3d(new Point3d(0.54942463156146, 0.471633229492457, 0.687724718029017), 0.45, new Vector3d(0.00234836551341398, -0.00168595290036738, 0.00407955171963179));\n            Circle3d c2 = new Circle3d(new Point3d(0.466918419682331, 0.557604272259504, 0.400167832409575), 0.45, new Vector3d(0.000185747980640577, 0.0018045609707127, 0.00465929795040716));\n            Assert.IsTrue(c1.IntersectionWith(c2) != null);\n            Assert.IsTrue(c2.IntersectionWith(c1) != null);\n            Assert.IsTrue(c1.Intersects(c2));\n            Assert.IsTrue(c2.Intersects(c1));\n\n        }\n\n        [TestMethod()]\n        public void CircleIntersectionWithCircle3DTest_7()\n        {\n            Circle3d c1 = new Circle3d(new Point3d(0.46372, 0.66101, 0.98636), 0.13411, new Vector3d(-0.43057, -0.46505, 0.77352));\n            Circle3d c2 = new Circle3d(new Point3d(0.26693, 0.63023, 0.69331), 0.38415, new Vector3d(0.66577, -0.42584, -0.6127));\n            Assert.IsTrue(c1.IntersectionWith(c2) != null);\n            Assert.IsTrue(c2.IntersectionWith(c1) != null);\n            Assert.IsTrue(c1.Intersects(c2));\n            Assert.IsTrue(c2.Intersects(c1));\n        }\n\n        [TestMethod()]\n        public void CircleDistanceToPlaneTest()\n        {\n            // Parallel circle\n            Plane3d p = new Plane3d(new Point3d(), new Vector3d(0, 0, 1));\n            Circle3d c = new Circle3d(new Point3d(10, 10, 10), 5, new Vector3d(0, 0, 1));\n            Assert.IsTrue(GeometRi3D.AlmostEqual(c.DistanceTo(p), 10));\n\n            // Orthogonal circle\n            c = new Circle3d(new Point3d(10, 10, 10), 5, new Vector3d(1, 1, 0));\n            Assert.IsTrue(GeometRi3D.AlmostEqual(c.DistanceTo(p), 5));\n\n            // Inclined circle\n            c = new Circle3d(new Point3d(10, 10, 10), 5, new Vector3d(3, 0, 4));\n            Assert.IsTrue(GeometRi3D.AlmostEqual(c.DistanceTo(p), 7));\n        }\n\n        [TestMethod()]\n        public void CircleDistanceToPointTest()\n        {\n            Circle3d c = new Circle3d(new Point3d(0, 0, 0), 5, new Vector3d(0, 0, 1));\n            Point3d p = new Point3d(2, 3, 4);\n            Assert.IsTrue(GeometRi3D.AlmostEqual(c.DistanceTo(p), 4));\n\n            p = new Point3d(4, 3, 0);\n            Assert.IsTrue(GeometRi3D.AlmostEqual(c.DistanceTo(p), 0));\n\n            p = new Point3d(2, 3, 0);\n            Assert.IsTrue(GeometRi3D.AlmostEqual(c.DistanceTo(p), 0));\n\n            p = new Point3d(8, 0, 4);\n            Assert.IsTrue(GeometRi3D.AlmostEqual(c.DistanceTo(p), 5));\n        }\n\n        [TestMethod()]\n        public void CircleDistanceToCircleTest()\n        {\n            Circle3d c1 = new Circle3d(new Point3d(0, 0, 0), 5, new Vector3d(0, 0, 1));\n            Circle3d c2 = new Circle3d(new Point3d(11, 0, 0), 5, new Vector3d(0, 0, 1));\n            Assert.IsTrue(GeometRi3D.AlmostEqual(c1.DistanceTo(c2), 1));\n\n            c2 = new Circle3d(new Point3d(11, 0, 0), 5, new Vector3d(0, 2, 1));\n            Assert.IsTrue(GeometRi3D.AlmostEqual(c1.DistanceTo(c2), 1));\n        }\n\n        [TestMethod()]\n        public void CircleDistanceToCircleTest_02()\n        {\n            Circle3d c1 = new Circle3d(new Point3d(0, 0, 0), 5, new Vector3d(0, 0, 1));\n            Circle3d c2 = new Circle3d(new Point3d(6, 20, 0), 19.9, new Vector3d(1, 0, 0));\n            double dist1 = c1.DistanceTo(c2);\n            double dist2 = (new Point3d(6, 0.1, 0)).DistanceTo(c1);\n            Assert.IsTrue(GeometRi3D.AlmostEqual(dist1, dist2));\n\n        }\n\n        [TestMethod()]\n        public void CircleDistanceToCircleGreaterTest()\n        {\n            Circle3d c1 = new Circle3d(new Point3d(0, 0, 0), 5, new Vector3d(0, 0, 1));\n            Circle3d c2 = new Circle3d(new Point3d(11, 0, 0), 5, new Vector3d(0, 0, 1));\n            Assert.IsTrue(c1.DistanceGreater(c2, 0.9, 1e-5));\n\n            c2 = new Circle3d(new Point3d(11, 0, 0), 5, new Vector3d(0, 1, 0));\n            Assert.IsTrue(c1.DistanceGreater(c2, 0.9, 1e-5));\n\n            c2 = new Circle3d(new Point3d(11, 0, 1), 5, new Vector3d(0, 0, 1));\n            Assert.IsTrue(c1.DistanceGreater(c2, 0.9, 1e-5));\n\n            c2 = new Circle3d(new Point3d(5, 0, 1), 5, new Vector3d(0, 0, 1));\n            Assert.IsTrue(c1.DistanceGreater(c2, 0.9, 1e-5));\n\n            c2 = new Circle3d(new Point3d(5, 0, 1), 5, new Vector3d(0.01, 0, 1));\n            Assert.IsTrue(c1.DistanceGreater(c2, 0.1, 1e-5));\n\n            c1 = new Circle3d(new Point3d(0.48856, 0.63565, 0.57343), 0.1, new Vector3d(0.40758, -0.78312, 0.46968));\n            c2 = new Circle3d(new Point3d(0.47796, 0.64711, 0.60481), 0.1, new Vector3d(0.43088, 0.14784, -0.89022));\n            Assert.IsFalse(c1.DistanceGreater(c2, 0.002, 1e-12));\n\n        }\n\n        [TestMethod()]\n        public void CircleToCircleClosestPointTest()\n        {\n            Point3d p1, p2;\n\n            // Nonintersecting circles in one plane\n            Circle3d c1 = new Circle3d(new Point3d(0, 0, 0), 5, new Vector3d(0, 0, 1));\n            Circle3d c2 = new Circle3d(new Point3d(11, 0, 0), 5, new Vector3d(0, 0, 1));\n            double dist = c1.DistanceTo(c2, out p1, out p2);\n            Assert.IsTrue(GeometRi3D.AlmostEqual(dist, p1.DistanceTo(p2)));\n\n            // Intersecting circles in one plane\n            c1 = new Circle3d(new Point3d(0, 0, 0), 5, new Vector3d(0, 0, 1));\n            c2 = new Circle3d(new Point3d(8, 0, 0), 5, new Vector3d(0, 0, 1));\n            dist = c1.DistanceTo(c2, out p1, out p2);\n            Assert.IsTrue(GeometRi3D.AlmostEqual(dist, p1.DistanceTo(p2)));\n\n            // Intersecting circles in one plane\n            c1 = new Circle3d(new Point3d(0, 0, 0), 5, new Vector3d(0, 0, 1));\n            c2 = new Circle3d(new Point3d(0, 0, 0), 3, new Vector3d(0, 0, 1));\n            dist = c1.DistanceTo(c2, out p1, out p2);\n            Assert.IsTrue(GeometRi3D.AlmostEqual(dist, p1.DistanceTo(p2)));\n\n            // Touching circles\n            c1 = new Circle3d(new Point3d(0, 0, 0), 5, new Vector3d(0, 0, 1));\n            c2 = new Circle3d(new Point3d(8, 0, 0), 3, new Vector3d(0, 0, 1));\n            dist = c1.DistanceTo(c2, out p1, out p2);\n            Assert.IsTrue(GeometRi3D.AlmostEqual(dist, p1.DistanceTo(p2)));\n\n            // Coplanar circles\n            c1 = new Circle3d(new Point3d(0, 0, 0), 5, new Vector3d(0, 0, 1));\n            c2 = new Circle3d(new Point3d(5, 0, 5), 3, new Vector3d(0, 0, 1));\n            dist = c1.DistanceTo(c2, out p1, out p2);\n            Assert.IsTrue(GeometRi3D.AlmostEqual(dist, p1.DistanceTo(p2)));\n\n            // Coplanar circles\n            c1 = new Circle3d(new Point3d(0, 0, 0), 5, new Vector3d(0, 0, 1));\n            c2 = new Circle3d(new Point3d(15, 0, 5), 3, new Vector3d(0, 0, 1));\n            dist = c1.DistanceTo(c2, out p1, out p2);\n            Assert.IsTrue(GeometRi3D.AlmostEqual(dist, p1.DistanceTo(p2)));\n\n            // Random circles\n            c1 = new Circle3d(new Point3d(2, 3, 0), 5, new Vector3d(4, -2, 1));\n            c2 = new Circle3d(new Point3d(15, 7, 5), 3, new Vector3d(2, 3, 1));\n            dist = c1.DistanceTo(c2, out p1, out p2);\n            Assert.IsTrue(GeometRi3D.AlmostEqual(dist, p1.DistanceTo(p2)));\n\n        }\n\n        [TestMethod()]\n        public void CircleParametricFormTest()\n        {\n            Circle3d c = new Circle3d(new Point3d(5, 6, 1), 5, new Vector3d(3, 0, 1));\n            Assert.IsTrue(c.ParametricForm(0.5).BelongsTo(c));\n        }\n\n        [TestMethod()]\n        public void CircleToEllipseTest()\n        {\n            Circle3d c = new Circle3d(new Point3d(5, 6, 1), 5, new Vector3d(3, 0, 1));\n            Ellipse e = c.ToEllipse;\n\n            Assert.IsTrue(c.ParametricForm(0.5).BelongsTo(e));\n            Assert.IsTrue(c.ParametricForm(0.725).BelongsTo(e));\n            Assert.IsTrue(c.ParametricForm(2.7215).BelongsTo(e));\n\n            Assert.IsTrue(e.ParametricForm(0.5).BelongsTo(c));\n            Assert.IsTrue(e.ParametricForm(0.725).BelongsTo(c));\n            Assert.IsTrue(e.ParametricForm(2.7215).BelongsTo(c));\n        }\n\n        [TestMethod()]\n        public void CircleProjectionToPlaneTest()\n        {\n            Vector3d v1 = new Vector3d(3, 5, 1);\n            Circle3d c = new Circle3d(new Point3d(5, 6, 1), 5, v1);\n            Plane3d s = new Plane3d(5, 2, 3, -3);\n\n            Point3d p = c.ParametricForm(0.5).ProjectionTo(s);\n            Assert.IsTrue(p.BelongsTo(c.ProjectionTo(s)));\n            p = c.ParametricForm(0.725).ProjectionTo(s);\n            Assert.IsTrue(p.BelongsTo(c.ProjectionTo(s)));\n            p = c.ParametricForm(2.7122).ProjectionTo(s);\n            Assert.IsTrue(p.BelongsTo(c.ProjectionTo(s)));\n        }\n\n        [TestMethod]\n        public void PointInCircleTest()\n        {\n            Point3d p = new Point3d(1, 1, 0);\n            Circle3d s = new Circle3d(p, 5, new Vector3d(0,0,1));\n\n            p = new Point3d(2, 2, 0);  // Point inside\n            Assert.IsTrue(p.BelongsTo(s));\n            Assert.IsTrue(p.IsInside(s));\n            Assert.IsFalse(p.IsOutside(s));\n            Assert.IsFalse(p.IsOnBoundary(s));\n\n            p = new Point3d(1, 6, 0);  // Point on boundary\n            Assert.IsTrue(p.BelongsTo(s));\n            Assert.IsFalse(p.IsInside(s));\n            Assert.IsFalse(p.IsOutside(s));\n            Assert.IsTrue(p.IsOnBoundary(s));\n\n            p = new Point3d(1, 6.005, 0);  // Point outside\n            Assert.IsFalse(p.BelongsTo(s));\n            Assert.IsFalse(p.IsInside(s));\n            Assert.IsTrue(p.IsOutside(s));\n            Assert.IsFalse(p.IsOnBoundary(s));\n\n            p = new Point3d(1, 2, 0.01);  // Point outside\n            Assert.IsFalse(p.BelongsTo(s));\n            Assert.IsFalse(p.IsInside(s));\n            Assert.IsTrue(p.IsOutside(s));\n            Assert.IsFalse(p.IsOnBoundary(s));\n        }\n\n        [TestMethod]\n        public void PointInCircleRelativeTest()\n        {\n            Point3d p = new Point3d(1, 1, 0);\n            Circle3d s = new Circle3d(p, 5, new Vector3d(0, 0, 1));\n\n            double tol = GeometRi3D.Tolerance;\n            bool mode = GeometRi3D.UseAbsoluteTolerance;\n            GeometRi3D.Tolerance = 0.01;\n            GeometRi3D.UseAbsoluteTolerance = false;\n\n            p = new Point3d(2, 2, 0.04);  // Point inside\n            Assert.IsTrue(p.BelongsTo(s));\n            Assert.IsTrue(p.IsInside(s));\n            Assert.IsFalse(p.IsOutside(s));\n            Assert.IsFalse(p.IsOnBoundary(s));\n\n            p = new Point3d(1, 6.04, 0);  // Point on boundary\n            Assert.IsTrue(p.BelongsTo(s));\n            Assert.IsFalse(p.IsInside(s));\n            Assert.IsFalse(p.IsOutside(s));\n            Assert.IsTrue(p.IsOnBoundary(s));\n\n            p = new Point3d(1, 6.06, 0);  // Point outside\n            Assert.IsFalse(p.BelongsTo(s));\n            Assert.IsFalse(p.IsInside(s));\n            Assert.IsTrue(p.IsOutside(s));\n            Assert.IsFalse(p.IsOnBoundary(s));\n\n            p = new Point3d(1, 2, 0.06);  // Point outside\n            Assert.IsFalse(p.BelongsTo(s));\n            Assert.IsFalse(p.IsInside(s));\n            Assert.IsTrue(p.IsOutside(s));\n            Assert.IsFalse(p.IsOnBoundary(s));\n\n            // Restore initial state\n            GeometRi3D.UseAbsoluteTolerance = mode;\n            GeometRi3D.Tolerance = tol;\n        }\n\n        [TestMethod()]\n        public void IsInsideBoxTest()\n        {\n            Box3d box = new Box3d();\n            Circle3d c = new Circle3d(new Point3d(0, 0, 0), 0.2, new Vector3d(0, 0, 1));\n            Assert.IsTrue(c.IsInside(box));\n            c = new Circle3d(new Point3d(5, 0, 0), 0.2, new Vector3d(0, 0, 1));\n            Assert.IsFalse(c.IsInside(box));\n            c = new Circle3d(new Point3d(0.9, 0, 0), 0.2, new Vector3d(0, 0, 1));\n            Assert.IsFalse(c.IsInside(box));\n        }\n\n        [TestMethod()]\n        public void CircleIntersectsSphereTest()\n        {\n            Point3d p = new Point3d();\n            Circle3d c = new Circle3d(p, 1.0, new Vector3d(0, 0, 1));\n\n            // Intersecting objects\n            Sphere s = new Sphere(new Point3d(0, 0, 1), 1.1);\n            Assert.IsTrue(c.Intersects(s));\n\n            s = new Sphere(new Point3d(0, 0, 0), 10);\n            Assert.IsTrue(c.Intersects(s));\n\n            s = new Sphere(new Point3d(2, 0, 0), 1.1);\n            Assert.IsTrue(c.Intersects(s));\n\n            // Touching objects\n            s = new Sphere(new Point3d(0, 0, 1), 1.0);\n            Assert.IsTrue(c.Intersects(s));\n\n            s = new Sphere(new Point3d(2, 0, 0), 1.0);\n            Assert.IsTrue(c.Intersects(s));\n\n            // Non-intersecting objects\n            s = new Sphere(new Point3d(3, 0, 0), 1.0);\n            Assert.IsFalse(c.Intersects(s));\n\n        }\n\n        [TestMethod()]\n        public void CircleDistanceToSphereTest()\n        {\n            Point3d p = new Point3d();\n            Circle3d c = new Circle3d(p, 1.0, new Vector3d(0, 0, 1));\n            Point3d p1, p2;\n\n            // Intersecting objects\n            Sphere s = new Sphere(new Point3d(0, 0, 1), 1.1);\n            double dist = c.DistanceTo(s, out p1, out p2);\n            Assert.AreEqual(dist, 0.0);\n            Assert.AreEqual(p1, new Point3d(0, 0, 0));\n            Assert.AreEqual(p2, new Point3d(0, 0, -0.1));\n\n            s = new Sphere(new Point3d(0, 0, 0), 10);\n            Assert.AreEqual(c.DistanceTo(s), 0.0);\n\n            s = new Sphere(new Point3d(2, 0, 0), 1.1);\n            dist = c.DistanceTo(s, out p1, out p2);\n            Assert.AreEqual(dist, 0.0);\n            Assert.AreEqual(p1, new Point3d(1, 0, 0));\n            Assert.AreEqual(p2, new Point3d(0.9, 0, 0));\n\n            // Touching objects\n            s = new Sphere(new Point3d(0, 0, 1), 1.0);\n            dist = c.DistanceTo(s, out p1, out p2);\n            Assert.AreEqual(dist, 0.0);\n            Assert.AreEqual(p1, new Point3d(0, 0, 0));\n            Assert.AreEqual(p2, new Point3d(0, 0, 0));\n\n            s = new Sphere(new Point3d(2, 0, 0), 1.0);\n            dist = c.DistanceTo(s, out p1, out p2);\n            Assert.AreEqual(dist, 0.0);\n            Assert.AreEqual(p1, new Point3d(1, 0, 0));\n            Assert.AreEqual(p2, new Point3d(1, 0, 0));\n\n            // Non-intersecting objects\n            s = new Sphere(new Point3d(3, 0, 0), 1.0);\n            dist = c.DistanceTo(s, out p1, out p2);\n            Assert.IsTrue(GeometRi3D.AlmostEqual(dist, 1.0));\n            Assert.AreEqual(p1, new Point3d(1, 0, 0));\n            Assert.AreEqual(p2, new Point3d(2, 0, 0));\n        }\n\n        [TestMethod()]\n        public void CircleDistanceToLineTest()\n        {\n            Point3d p = new Point3d();\n            Circle3d c = new Circle3d(p, 1.0, new Vector3d(0, 0, 1));\n            Point3d p1, p2;\n\n            // Parallel objects\n            Line3d l= new Line3d(new Point3d(0, 0, 1), new Vector3d(1, 0, 0));\n            double dist = c.DistanceTo(l, out p1, out p2);\n            Assert.AreEqual(dist, 1.0);\n            Assert.AreEqual(p1, p);\n            Assert.AreEqual(p2, new Point3d(0, 0, 1));\n\n            // Coplanar intersecting objects\n            l = new Line3d(new Point3d(0, 0.5, 0), new Vector3d(1, 0, 0));\n            dist = c.DistanceTo(l, out p1, out p2);\n            Assert.AreEqual(dist, 0.0);\n            Assert.AreEqual(p1, new Point3d(0, 0.5, 0));\n            Assert.AreEqual(p2, new Point3d(0, 0.5, 0));\n\n            // Coplanar non-intersecting objects\n            l = new Line3d(new Point3d(0, 1.5, 0), new Vector3d(1, 0, 0));\n            dist = c.DistanceTo(l, out p1, out p2);\n            Assert.AreEqual(dist, 0.5);\n            Assert.AreEqual(p1, new Point3d(0, 1, 0));\n            Assert.AreEqual(p2, new Point3d(0, 1.5, 0));\n\n            // Intersecting objects\n            l = new Line3d(new Point3d(0, 0.5, 0), new Vector3d(0, 0, 1));\n            dist = c.DistanceTo(l, out p1, out p2);\n            Assert.AreEqual(dist, 0.0);\n            Assert.AreEqual(p1, new Point3d(0, 0.5, 0));\n            Assert.AreEqual(p2, new Point3d(0, 0.5, 0));\n\n            // Non-intersecting objects\n            l = new Line3d(new Point3d(0, 1.5, 0), new Vector3d(0, 0, 1));\n            dist = c.DistanceTo(l, out p1, out p2);\n            Assert.AreEqual(dist, 0.5);\n            Assert.AreEqual(p1, new Point3d(0, 1, 0));\n            Assert.AreEqual(p2, new Point3d(0, 1.5, 0));\n\n            // Non-intersecting objects\n            l = new Line3d(new Point3d(0, 1.5, 0), new Vector3d(1, 0, 1));\n            dist = c.DistanceTo(l, out p1, out p2);\n            Assert.AreEqual(dist, 0.5);\n            Assert.AreEqual(p1, new Point3d(0, 1, 0));\n            Assert.AreEqual(p2, new Point3d(0, 1.5, 0));\n        }\n\n        [TestMethod()]\n        public void CircleClosestPointToPlaneTest()\n        {\n            Point3d p = new Point3d(0, 0, 5);\n            Circle3d c = new Circle3d(p, 1.0, new Vector3d(0, 0, 1));\n            Plane3d plane = new Plane3d(new Point3d(), new Vector3d(0, 0, 1));\n            Point3d p1, p2;\n\n            // Parallel objects\n            double dist = c.DistanceTo(plane, out p1, out p2);\n            Assert.AreEqual(dist, 5.0);\n            Assert.AreEqual(p1, p);\n            Assert.AreEqual(p2, new Point3d(0, 0, 0));\n\n            // Non-parallel objects\n            c = new Circle3d(p, 1.0, new Vector3d(1, 0, 0));\n            dist = c.DistanceTo(plane, out p1, out p2);\n            Assert.AreEqual(dist, 4.0);\n            Assert.AreEqual(p1, new Point3d(0, 0, 4));\n            Assert.AreEqual(p2, new Point3d(0, 0, 0));\n        }\n\n        [TestMethod()]\n        public void CircleClosestPointToTriangleTest()\n        {\n            Point3d p1 = new Point3d(0, 0, 0);\n            Point3d p2 = new Point3d(5, 0, 0);\n            Point3d p3 = new Point3d(0, 5, 0);\n            Triangle t = new Triangle(p1, p2, p3);\n\n            Point3d pc, pt;\n\n            // Circle in triangle\n            Circle3d c = new Circle3d(new Point3d(2, 2, 0), 1, new Vector3d(0, 0, 1));\n            double dist = c.DistanceTo(t, out pc, out pt);\n            Assert.AreEqual(dist, 0.0);\n            Assert.AreEqual(pc, new Point3d(2, 2, 0));\n            Assert.AreEqual(pt, new Point3d(2, 2, 0));\n\n            // Triangle in circle\n            c = new Circle3d(new Point3d(5, 5, 0), 10, new Vector3d(0, 0, 1));\n            dist = c.DistanceTo(t, out pc, out pt);\n            Assert.AreEqual(dist, 0.0);\n            Assert.AreEqual(pc, pt);\n            Assert.IsTrue(pc.BelongsTo(c));\n            Assert.IsTrue(pt.BelongsTo(t));\n\n            // Closest point at vertex\n            c = new Circle3d(new Point3d(-2, -2, 0), Sqrt(2), new Vector3d(0, 0, 1));\n            dist = c.DistanceTo(t, out pc, out pt);\n            Assert.AreEqual(dist, Sqrt(2.0));\n            Assert.AreEqual(pc, new Point3d(-1, -1, 0));\n            Assert.AreEqual(pt, p1);\n\n            // Closest point at edge\n            c = new Circle3d(new Point3d(2, -2, 0), 1, new Vector3d(0, 0, 1));\n            dist = c.DistanceTo(t, out pc, out pt);\n            Assert.AreEqual(dist, 1.0);\n            Assert.AreEqual(pc, new Point3d(2, -1, 0));\n            Assert.AreEqual(pt, new Point3d(2, 0, 0));\n\n        }\n\n        [TestMethod()]\n        public void CircleBoundaryDistanceToLineTest()\n        {\n            Point3d p = new Point3d();\n            Circle3d c = new Circle3d(p, 1.0, new Vector3d(0, 0, 1));\n            Point3d point_on_circle, point_on_line;\n\n            // Parallel objects\n            Line3d l = new Line3d(new Point3d(0, 2, 1), new Vector3d(1, 0, 0));\n            double dist = c.DistanceToBoundary(l, out point_on_circle, out point_on_line);\n            Assert.AreEqual(dist, Sqrt(2));\n            Assert.AreEqual(point_on_circle, new Point3d(0, 1, 0));\n            Assert.AreEqual(point_on_line, new Point3d(0, 2, 1));\n\n            l = new Line3d(new Point3d(0, 1, 1), new Vector3d(1, 0, 0));\n            dist = c.DistanceToBoundary(l, out point_on_circle, out point_on_line);\n            Assert.AreEqual(dist, 1);\n            Assert.AreEqual(point_on_circle, new Point3d(0, 1, 0));\n            Assert.AreEqual(point_on_line, new Point3d(0, 1, 1));\n\n            l = new Line3d(new Point3d(0, 0, 1), new Vector3d(1, 0, 0));\n            dist = c.DistanceToBoundary(l, out point_on_circle, out point_on_line);\n            Assert.AreEqual(dist, 1);\n            Assert.AreEqual(point_on_circle, new Point3d(1, 0, 0));\n            Assert.AreEqual(point_on_line, new Point3d(1, 0, 1));\n\n            // Coplanar intersecting objects\n            l = new Line3d(new Point3d(0, 1, 0), new Vector3d(1, 0, 0));\n            dist = c.DistanceToBoundary(l, out point_on_circle, out point_on_line);\n            Assert.AreEqual(dist, 0);\n            Assert.AreEqual(point_on_circle, new Point3d(0, 1, 0));\n            Assert.AreEqual(point_on_line, new Point3d(0, 1, 0));\n\n\n            // Coplanar non-intersecting objects\n            l = new Line3d(new Point3d(0, 2, 0), new Vector3d(1, 0, 0));\n            dist = c.DistanceToBoundary(l, out point_on_circle, out point_on_line);\n            Assert.AreEqual(dist, 1);\n            Assert.AreEqual(point_on_circle, new Point3d(0, 1, 0));\n            Assert.AreEqual(point_on_line, new Point3d(0, 2, 0));\n\n\n            // Intersecting objects\n            l = new Line3d(new Point3d(1, 0, 0), new Vector3d(1, 0, 1));\n            dist = c.DistanceToBoundary(l, out point_on_circle, out point_on_line);\n            Assert.IsTrue(GeometRi3D.AlmostEqual(dist, 0));\n            Assert.AreEqual(point_on_circle, new Point3d(1, 0, 0));\n            Assert.AreEqual(point_on_line, new Point3d(1, 0, 0));\n\n\n            // Non-intersecting objects\n            l = new Line3d(new Point3d(0, 0, 0), new Vector3d(1, 0, 1));\n            dist = c.DistanceToBoundary(l, out point_on_circle, out point_on_line);\n            Assert.IsTrue(GeometRi3D.AlmostEqual(dist, Sqrt(0.5)));\n            Assert.AreEqual(point_on_circle, new Point3d(-1, 0, 0));\n            Assert.AreEqual(point_on_line, new Point3d(-0.5, 0, -0.5));\n\n        }\n\n\n    }\n}\n"
  },
  {
    "path": "GeometRi.Tests/ConvexPolyhedronTest.cs",
    "content": "﻿using System;\nusing static System.Math;\nusing Microsoft.VisualStudio.TestTools.UnitTesting;\nusing GeometRi;\n\nnamespace GeometRi_Tests\n{\n    [TestClass]\n    public class ConvexPolyhedronTest\n    {\n        [TestMethod]\n        public void AreaVolumeTest()\n        {\n            int count = 200;\n            for (int i = 0; i < count; i++)\n            {\n                Tetrahedron t1 = Tetrahedron.Random();\n                ConvexPolyhedron c1 = ConvexPolyhedron.FromTetrahedron(t1);\n                Assert.IsTrue(Abs(t1.Area - c1.Area) < GeometRi3D.Tolerance);\n                Assert.IsTrue(Abs(t1.Volume - c1.Volume) < GeometRi3D.Tolerance);\n            }\n        }\n\n        [TestMethod]\n        public void TetrahedronIntersectionCheckTest()\n        {\n            int count = 200;\n\n            // Likely intersecting tetrahedrones\n            for (int i=0; i < count; i++)\n            {\n                Tetrahedron t1 = Tetrahedron.Random();\n                Tetrahedron t2 = Tetrahedron.Random();\n                // Exclude close to degenerate tetrahednones\n                if (t1.Volume > 0.1 && t2.Volume > 0.1)\n                {\n                    ConvexPolyhedron c1 = ConvexPolyhedron.FromTetrahedron(t1);\n                    ConvexPolyhedron c2 = ConvexPolyhedron.FromTetrahedron(t2);\n                    Assert.AreEqual(t1.Intersects(t2), c1.Intersects(c2));\n                }\n            }\n\n            // Close non-intersecting tetrahedrones\n            for (int i = 0; i < count; i++)\n            {\n                Tetrahedron t1 = Tetrahedron.Random();\n                Tetrahedron t2 = Tetrahedron.Random().Translate(new Vector3d(1, 0, 0));\n                // Exclude close to degenerate tetrahednones\n                if (t1.Volume > 0.05 && t2.Volume > 0.05)\n                {\n                    ConvexPolyhedron c1 = ConvexPolyhedron.FromTetrahedron(t1);\n                    ConvexPolyhedron c2 = ConvexPolyhedron.FromTetrahedron(t2);\n                    Assert.AreEqual(t1.Intersects(t2), c1.Intersects(c2));\n                }\n            }\n\n            // Far non-intersecting tetrahedrones\n            for (int i = 0; i < count; i++)\n            {\n                Tetrahedron t1 = Tetrahedron.Random();\n                Tetrahedron t2 = Tetrahedron.Random().Translate(new Vector3d(100, 0, 0));\n                // Exclude close to degenerate tetrahednones\n                if (t1.Volume > 0.05 && t2.Volume > 0.05)\n                {\n                    ConvexPolyhedron c1 = ConvexPolyhedron.FromTetrahedron(t1);\n                    ConvexPolyhedron c2 = ConvexPolyhedron.FromTetrahedron(t2);\n                    Assert.AreEqual(t1.Intersects(t2), c1.Intersects(c2));\n                }\n            }\n\n        }\n\n        [TestMethod]\n        public void ConvexPolyhedronIntersectionCheckTest_01()\n        {\n            Box3d box = new Box3d(new Point3d(0.5, 0.5, 0.5), 1, 1, 1);\n\n            Point3d A = new Point3d(0.62055, 1.2952, 0.89845);\n            Point3d B = new Point3d(0.47681, 1.1381, 0.91592);\n            Point3d C = new Point3d(0.60429, 0.96027, 1.0405);\n            Point3d D = new Point3d(0.54816, 1.256, 1.2097);\n            Tetrahedron t = new Tetrahedron(A, B, C, D);\n\n            ConvexPolyhedron cp_box = ConvexPolyhedron.FromBox(box);\n            ConvexPolyhedron cp_t = ConvexPolyhedron.FromTetrahedron(t);\n\n            Assert.IsFalse(cp_t.Intersects(cp_box));\n        }\n\n        [TestMethod]\n        public void ConvexPolyhedronIntersectionCheckTest_02()\n        {\n            Point3d A = new Point3d(0.75189, 0.047671, 0.64089);\n            Point3d B = new Point3d(0.69441, 0.26369, 0.8156);\n            Point3d C = new Point3d(1.0126, 0.26195, 0.71716);\n            Point3d D = new Point3d(0.73275, 0.41057, 0.61468);\n            Tetrahedron t1 = new Tetrahedron(A, B, C, D);\n\n            A = new Point3d(0.91294, 0.095756, 0.74814);\n            B = new Point3d(0.95606, 0.28099, 1.0639);\n            C = new Point3d(1.2819, 0.22197, 0.84984);\n            D = new Point3d(0.9913, 0.4657, 0.74708);\n            Tetrahedron t2 = new Tetrahedron(A, B, C, D);\n\n            ConvexPolyhedron cp_t1 = ConvexPolyhedron.FromTetrahedron(t1);\n            ConvexPolyhedron cp_t2 = ConvexPolyhedron.FromTetrahedron(t2);\n\n            Assert.IsFalse(cp_t1.Intersects(cp_t2));\n        }\n\n        [TestMethod]\n        public void ConvexPolyhedronIntersectionCheckTest_03()\n        {\n            Point3d A = new Point3d(0.051634, 0.391, 0.75902);\n            Point3d B = new Point3d(0.056938, 0.50361, 0.89111);\n            Point3d C = new Point3d(0.27042, 0.38715, 0.89053);\n            Point3d D = new Point3d(0.27694, 0.50134, 0.76028);\n            Tetrahedron t1 = new Tetrahedron(A, B, C, D);\n\n            A = new Point3d(-0.074466, 0.46362, 1.1418);\n            B = new Point3d(0.13639, 0.66447, 0.99967);\n            C = new Point3d(0.06711, 0.44386, 0.77189);\n            D = new Point3d(-0.19346, 0.62704, 0.84602);\n            Tetrahedron t2 = new Tetrahedron(A, B, C, D);\n\n            ConvexPolyhedron cp_t1 = ConvexPolyhedron.FromTetrahedron(t1);\n            ConvexPolyhedron cp_t2 = ConvexPolyhedron.FromTetrahedron(t2);\n\n            Assert.IsTrue(cp_t1.Intersects(cp_t2));\n        }\n\n        [TestMethod]\n        public void ConvexPolyhedronIntersectionCheckTest_04()\n        {\n            Point3d A = new Point3d(0.251097013104677, 0.546703145796848, 0.495434613743138);\n            Point3d B = new Point3d(0.291709439728301, 0.578882461419393, 0.650931851386847);\n            Point3d C = new Point3d(0.128566597389787, 0.440248968316735, 0.605189321180178);\n            Point3d D = new Point3d(0.350216056201755, 0.391985311884308, 0.582693942204766);\n            Tetrahedron t1 = new Tetrahedron(A, B, C, D);\n\n            A = new Point3d(0.121116388215459, 0.361753267278295, 0.898825185911191);\n            B = new Point3d(-0.00140768874670161, 0.573928160961876, 0.666186244206548);\n            C = new Point3d(0.175804665188155, 0.740808551308965, 0.844898958033819);\n            D = new Point3d(0.222857195023536, 0.471956639099317, 0.598778318291477);\n            Tetrahedron t2 = new Tetrahedron(A, B, C, D);\n\n            ConvexPolyhedron cp_t1 = ConvexPolyhedron.FromTetrahedron(t1);\n            ConvexPolyhedron cp_t2 = ConvexPolyhedron.FromTetrahedron(t2);\n\n            Assert.IsTrue(cp_t1.Intersects(cp_t2));\n        }\n\n        [TestMethod]\n        public void TetrahedronDistanceTest()\n        {\n            int count = 200;\n\n            // Likely intersecting tetrahedrones\n            for (int i = 0; i < count; i++)\n            {\n                Tetrahedron t1 = Tetrahedron.Random();\n                Tetrahedron t2 = Tetrahedron.Random();\n                // Exclude close to degenerate tetrahednones\n                if (t1.Volume > 0.1 && t2.Volume > 0.1)\n                {\n                    ConvexPolyhedron c1 = ConvexPolyhedron.FromTetrahedron(t1);\n                    ConvexPolyhedron c2 = ConvexPolyhedron.FromTetrahedron(t2);\n                    double dist1 = t1.DistanceTo(t2);\n                    double dist2 = c1.DistanceTo(c2);\n                    Assert.IsTrue(Abs(dist1-dist2) < 1e-10);\n                }\n            }\n\n            // Close non-intersecting tetrahedrones\n            for (int i = 0; i < count; i++)\n            {\n                Tetrahedron t1 = Tetrahedron.Random();\n                Tetrahedron t2 = Tetrahedron.Random().Translate(new Vector3d(1, 0, 0));\n                // Exclude close to degenerate tetrahednones\n                if (t1.Volume > 0.05 && t2.Volume > 0.05)\n                {\n                    ConvexPolyhedron c1 = ConvexPolyhedron.FromTetrahedron(t1);\n                    ConvexPolyhedron c2 = ConvexPolyhedron.FromTetrahedron(t2);\n                    double dist1 = t1.DistanceTo(t2);\n                    double dist2 = c1.DistanceTo(c2);\n                    Assert.IsTrue(Abs(dist1 - dist2) < 1e-10);\n                }\n            }\n\n            // Far non-intersecting tetrahedrones\n            for (int i = 0; i < count; i++)\n            {\n                Tetrahedron t1 = Tetrahedron.Random();\n                Tetrahedron t2 = Tetrahedron.Random().Translate(new Vector3d(10, 0, 0));\n                // Exclude close to degenerate tetrahednones\n                if (t1.Volume > 0.05 && t2.Volume > 0.05)\n                {\n                    ConvexPolyhedron c1 = ConvexPolyhedron.FromTetrahedron(t1);\n                    ConvexPolyhedron c2 = ConvexPolyhedron.FromTetrahedron(t2);\n                    double dist1 = t1.DistanceTo(t2);\n                    double dist2 = c1.DistanceTo(c2);\n                    Assert.IsTrue(Abs(dist1 - dist2) < 1e-10);\n                }\n            }\n\n        }\n\n        [TestMethod()]\n        public void TetrahedronDistanceToTetrahedronTest_01()\n        {\n            Point3d p0 = new Point3d(1.18847041209228, 0.104193542059284, 0.35298291672622);\n            Point3d p1 = new Point3d(0.649467768945706, 0.170331494522815, 0.72174959083238);\n            Point3d p2 = new Point3d(1.15947687723363, 0.573922428456402, 0.810586551138034);\n            Point3d p3 = new Point3d(0.793812982683988, 0.621719485201377, 0.267546685570428);\n            Tetrahedron t1 = new Tetrahedron(p0, p1, p2, p3);\n\n            Point3d s0 = new Point3d(0.216267039810085, 0.169909202890096, 0.859064204525464);\n            Point3d s1 = new Point3d(0.205044294164905, 0.659002041871181, 0.42140088318818);\n            Point3d s2 = new Point3d(0.66494259923399, 0.648073860241189, 0.889654085897164);\n            Point3d s3 = new Point3d(0.684153131501953, 0.210778895931041, 0.400480284835266);\n            Tetrahedron t2 = new Tetrahedron(s0, s1, s2, s3);\n\n            ConvexPolyhedron c1 = ConvexPolyhedron.FromTetrahedron(t1);\n            ConvexPolyhedron c2 = ConvexPolyhedron.FromTetrahedron(t2);\n\n            double dist = c1.DistanceTo(c2);\n            double dist2 = c2.DistanceTo(c1);\n\n            Assert.IsTrue(dist > 0.02562);\n            Assert.IsTrue(dist2 > 0.02562);\n\n            bool check1 = c1.Intersects(c2);\n            bool check2 = c2.Intersects(c1);\n            Assert.IsFalse(c1.Intersects(c2));\n            Assert.IsFalse(c2.Intersects(c1));\n        }\n\n        [TestMethod]\n        public void BoxIntersectionTest()\n        {\n            Box3d b = new Box3d();\n            Tetrahedron t = new Tetrahedron();\n\n            ConvexPolyhedron cb = ConvexPolyhedron.FromBox(b);\n            ConvexPolyhedron ct = ConvexPolyhedron.FromTetrahedron(t);\n            Assert.IsTrue(ct.Intersects(cb));\n\n            cb = cb.Translate(new Vector3d(1, 0, 0));\n            Assert.IsTrue(ct.Intersects(cb));\n\n            cb = cb.Translate(new Vector3d(1, 0, 0));\n            Assert.IsFalse(ct.Intersects(cb));\n        }\n\n        [TestMethod]\n        public void OctahedronIntersectionCheckTest_03()\n        {\n\n            ConvexPolyhedron cp1 = ConvexPolyhedron.Octahedron();\n            ConvexPolyhedron cp2 = ConvexPolyhedron.Octahedron();\n\n            cp1 = cp1.Translate(new Vector3d(0.9, 0, 0));\n\n            Assert.IsTrue(cp1.Intersects(cp2));\n        }\n\n        [TestMethod]\n        public void IcosahedronIntersectionCheckTest_03()\n        {\n\n            ConvexPolyhedron cp1 = ConvexPolyhedron.Icosahedron();\n            ConvexPolyhedron cp2 = ConvexPolyhedron.Icosahedron();\n\n            cp1 = cp1.Translate(new Vector3d(1.5, 0, 0));\n\n            Assert.IsTrue(cp1.Intersects(cp2));\n        }\n\n        [TestMethod]\n        public void DodecaahedronIntersectionCheckTest_03()\n        {\n\n            ConvexPolyhedron cp1 = ConvexPolyhedron.Dodecahedron();\n            ConvexPolyhedron cp2 = ConvexPolyhedron.Dodecahedron();\n\n            cp2 = cp2.Translate(new Vector3d(1.5, 0, 0));\n            Assert.IsTrue(cp1.Intersects(cp2));\n\n            cp2 = cp2.Translate(new Vector3d(1.5, 0, 0));\n            Assert.IsTrue(cp1.Intersects(cp2));\n        }\n\n        [TestMethod]\n        public void CopyTest()\n        {\n            Tetrahedron t = new Tetrahedron();\n            ConvexPolyhedron ct = ConvexPolyhedron.FromTetrahedron(t);\n            ConvexPolyhedron copy = ct.Copy();\n            Assert.AreEqual(ct.Volume, copy.Volume);\n        }\n\n        [TestMethod]\n        public void BoxBoxDistanceTest_01()\n        {\n            Box3d b1 = new Box3d(new Point3d(0, 0, 0), 1, 1, 1);\n            Box3d b2 = new Box3d(new Point3d(2, 0, 0), 1, 1, 1);\n            ConvexPolyhedron cp1 = ConvexPolyhedron.FromBox(b1);\n            ConvexPolyhedron cp2 = ConvexPolyhedron.FromBox(b2);\n            Point3d p1, p2;\n            double dist = cp1.DistanceTo(cp2, out p1, out p2);\n            Assert.AreEqual(dist, 1);\n        }\n\n        [TestMethod]\n        public void BoxBoxDistanceTest_02()\n        {\n            // Touching boxes\n            Box3d b1 = new Box3d(new Point3d(0, 0, 0), 1, 1, 1);\n            Box3d b2 = new Box3d(new Point3d(1, 0.5, 0.5), 1, 1, 1);\n            ConvexPolyhedron cp1 = ConvexPolyhedron.FromBox(b1);\n            ConvexPolyhedron cp2 = ConvexPolyhedron.FromBox(b2);\n            Point3d p1, p2;\n            double dist = cp1.DistanceTo(cp2, out p1, out p2);\n            Assert.AreEqual(dist, 0);\n            Assert.IsTrue(p1.BelongsTo(cp1));\n            Assert.IsTrue(p2.BelongsTo(cp2));\n        }\n\n        [TestMethod]\n        public void BoxBoxDistanceTest_03()\n        {\n            // Partially intersecting boxes\n            Box3d b1 = new Box3d(new Point3d(0, 0, 0), 1, 1, 1);\n            Box3d b2 = new Box3d(new Point3d(0.5, 0.5, 0.5), 1, 1, 1);\n            ConvexPolyhedron cp1 = ConvexPolyhedron.FromBox(b1);\n            ConvexPolyhedron cp2 = ConvexPolyhedron.FromBox(b2);\n            Point3d p1, p2;\n            double dist = cp1.DistanceTo(cp2, out p1, out p2);\n            Assert.AreEqual(dist, 0);\n            Assert.IsTrue(p1.BelongsTo(cp1));\n            Assert.IsTrue(p2.BelongsTo(cp2));\n        }\n\n        [TestMethod]\n        public void BoxBoxDistanceTest_04()\n        {\n            // Non-intersecting boxes\n            Box3d b1 = new Box3d(new Point3d(0, 0, 0), new Point3d(1, 1, 1));\n            Box3d b2 = new Box3d(new Point3d(2, 2, 2), new Point3d(3, 3, 3));\n            ConvexPolyhedron cp1 = ConvexPolyhedron.FromBox(b1);\n            ConvexPolyhedron cp2 = ConvexPolyhedron.FromBox(b2);\n            Point3d p1, p2;\n            double dist = cp1.DistanceTo(cp2, out p1, out p2);\n            Assert.IsTrue(GeometRi3D.AlmostEqual(dist, Sqrt(3)));\n            Assert.IsTrue(p1.BelongsTo(cp1));\n            Assert.IsTrue(p2.BelongsTo(cp2));\n        }\n\n        [TestMethod]\n        public void BoxTetDistanceTest_04()\n        {\n            // Non-intersecting boxes\n            Box3d b1 = new Box3d(new Point3d(0, 0, 0), new Point3d(1, 1, 1));\n            Tetrahedron b2 = new Tetrahedron(new Point3d(2, 2, 2), new Point3d(3.01, 3, 3), new Point3d(3, 3.01, 3), new Point3d(3, 3, 3.01));\n            ConvexPolyhedron cp1 = ConvexPolyhedron.FromBox(b1);\n            ConvexPolyhedron cp2 = ConvexPolyhedron.FromTetrahedron(b2);\n            Point3d p1, p2;\n            double dist = cp1.DistanceTo(cp2, out p1, out p2);\n            Assert.IsTrue(GeometRi3D.AlmostEqual(dist, Sqrt(3)));\n            Assert.IsTrue(p1.BelongsTo(cp1));\n            Assert.IsTrue(p2.BelongsTo(cp2));\n        }\n\n        [TestMethod]\n        public void TetTetDistanceTest_01()\n        {\n            // Vertex-Vertex distance\n            Tetrahedron t1 = new Tetrahedron(new Point3d(0, 0, 0), new Point3d(-1, -1, -1), new Point3d(-1, -1, 1), new Point3d(-1, 1, 1));\n            Tetrahedron t2 = new Tetrahedron(new Point3d(0.5, 0, 0), new Point3d(1, -1, -1), new Point3d(1, -1, 1), new Point3d(1, 1, 1));\n            ConvexPolyhedron cp1 = ConvexPolyhedron.FromTetrahedron(t1);\n            ConvexPolyhedron cp2 = ConvexPolyhedron.FromTetrahedron(t2);\n            Point3d p1 = new Point3d();\n            Point3d p2 = new Point3d();\n            double dist = cp1.DistanceTo(cp2, out p1, out p2);\n            Assert.IsTrue(GeometRi3D.AlmostEqual(dist, 0.5));\n            Assert.IsTrue(p1 == new Point3d(0, 0, 0));\n            Assert.IsTrue(p2 == new Point3d(0.5, 0, 0));\n        }\n\n        [TestMethod]\n        public void TetTetDistanceTest_02()\n        {\n            // Vertex-Edge distance\n            Tetrahedron t1 = new Tetrahedron(new Point3d(0, 0, 0), new Point3d(-1, -1, -1), new Point3d(-1, -1, 1), new Point3d(-1, 1, 1));\n            Tetrahedron t2 = new Tetrahedron(new Point3d(0.5, -1, 0), new Point3d(0.5, 1, 0), new Point3d(1, 0, -1), new Point3d(1, 0, 1));\n            ConvexPolyhedron cp1 = ConvexPolyhedron.FromTetrahedron(t1);\n            ConvexPolyhedron cp2 = ConvexPolyhedron.FromTetrahedron(t2);\n            Point3d p1 = new Point3d();\n            Point3d p2 = new Point3d();\n            double dist = cp1.DistanceTo(cp2, out p1, out p2);\n            Assert.IsTrue(GeometRi3D.AlmostEqual(dist, 0.5));\n            Assert.IsTrue(p1 == new Point3d(0, 0, 0));\n            Assert.IsTrue(p2 == new Point3d(0.5, 0, 0));\n        }\n\n        [TestMethod]\n        public void TetTetDistanceTest_03()\n        {\n            // Vertex-Face distance\n            Tetrahedron t1 = new Tetrahedron(new Point3d(0, 0, 0), new Point3d(-1, -1, -1), new Point3d(-1, -1, 1), new Point3d(-1, 1, 1));\n            Tetrahedron t2 = new Tetrahedron(new Point3d(0.5, -1, -1), new Point3d(0.5, 1, -1), new Point3d(0.5, 0, 1), new Point3d(1, 0, 0));\n            ConvexPolyhedron cp1 = ConvexPolyhedron.FromTetrahedron(t1);\n            ConvexPolyhedron cp2 = ConvexPolyhedron.FromTetrahedron(t2);\n            Point3d p1 = new Point3d();\n            Point3d p2 = new Point3d();\n            double dist = cp1.DistanceTo(cp2, out p1, out p2);\n            Assert.IsTrue(GeometRi3D.AlmostEqual(dist, 0.5));\n            Assert.IsTrue(p1 == new Point3d(0, 0, 0));\n            Assert.IsTrue(p2 == new Point3d(0.5, 0, 0));\n        }\n\n        [TestMethod]\n        public void TetTetDistanceTest_04()\n        {\n            // Edge-Edge distance\n            Tetrahedron t1 = new Tetrahedron(new Point3d(0, 0, -1), new Point3d(0, 0, 1), new Point3d(-1, -1, 0), new Point3d(-1, 1, 0));\n            Tetrahedron t2 = new Tetrahedron(new Point3d(0.5, -1, 0), new Point3d(0.5, 1, 0), new Point3d(1, 0, -1), new Point3d(1, 0, 1));\n            ConvexPolyhedron cp1 = ConvexPolyhedron.FromTetrahedron(t1);\n            ConvexPolyhedron cp2 = ConvexPolyhedron.FromTetrahedron(t2);\n            Point3d p1 = new Point3d();\n            Point3d p2 = new Point3d();\n            double dist = cp1.DistanceTo(cp2, out p1, out p2);\n            Assert.IsTrue(GeometRi3D.AlmostEqual(dist, 0.5));\n            Assert.IsTrue(p1 == new Point3d(0, 0, 0));\n            Assert.IsTrue(p2 == new Point3d(0.5, 0, 0));\n        }\n\n        [TestMethod]\n        public void TetTetDistanceTest_05()\n        {\n            // Vertex-Vertex touching\n            Tetrahedron t1 = new Tetrahedron(new Point3d(0, 0, 0), new Point3d(-1, -1, -1), new Point3d(-1, -1, 1), new Point3d(-1, 1, 1));\n            Tetrahedron t2 = new Tetrahedron(new Point3d(0, 0, 0), new Point3d(1, -1, -1), new Point3d(1, -1, 1), new Point3d(1, 1, 1));\n            ConvexPolyhedron cp1 = ConvexPolyhedron.FromTetrahedron(t1);\n            ConvexPolyhedron cp2 = ConvexPolyhedron.FromTetrahedron(t2);\n            double dist = cp1.DistanceTo(cp2);\n            Assert.IsTrue(GeometRi3D.AlmostEqual(dist, 0));\n        }\n\n        [TestMethod]\n        public void TetTetDistanceTest_06()\n        {\n            // Vertex-Edge touching\n            Tetrahedron t1 = new Tetrahedron(new Point3d(0, 0, 0), new Point3d(-1, -1, -1), new Point3d(-1, -1, 1), new Point3d(-1, 1, 1));\n            Tetrahedron t2 = new Tetrahedron(new Point3d(0, -1, 0), new Point3d(0, 1, 0), new Point3d(1, 0, -1), new Point3d(1, 0, 1));\n            ConvexPolyhedron cp1 = ConvexPolyhedron.FromTetrahedron(t1);\n            ConvexPolyhedron cp2 = ConvexPolyhedron.FromTetrahedron(t2);\n            double dist = cp1.DistanceTo(cp2);\n            Assert.IsTrue(GeometRi3D.AlmostEqual(dist, 0));\n        }\n\n        [TestMethod]\n        public void TetTetDistanceTest_07()\n        {\n            // Vertex-Face touching\n            Tetrahedron t1 = new Tetrahedron(new Point3d(0, 0, 0), new Point3d(-1, -1, -1), new Point3d(-1, -1, 1), new Point3d(-1, 1, 1));\n            Tetrahedron t2 = new Tetrahedron(new Point3d(0, -1, -1), new Point3d(0, 1, -1), new Point3d(0, 0, 1), new Point3d(1, 0, 0));\n            ConvexPolyhedron cp1 = ConvexPolyhedron.FromTetrahedron(t1);\n            ConvexPolyhedron cp2 = ConvexPolyhedron.FromTetrahedron(t2);\n            double dist = cp1.DistanceTo(cp2);\n            Assert.IsTrue(GeometRi3D.AlmostEqual(dist, 0));\n        }\n\n        [TestMethod]\n        public void TetTetDistanceTest_08()\n        {\n            // Edge-Edge touching\n            Tetrahedron t1 = new Tetrahedron(new Point3d(0, 0, -1), new Point3d(0, 0, 1), new Point3d(-1, -1, 0), new Point3d(-1, 1, 0));\n            Tetrahedron t2 = new Tetrahedron(new Point3d(0, -1, 0), new Point3d(0, 1, 0), new Point3d(1, 0, -1), new Point3d(1, 0, 1));\n            ConvexPolyhedron cp1 = ConvexPolyhedron.FromTetrahedron(t1);\n            ConvexPolyhedron cp2 = ConvexPolyhedron.FromTetrahedron(t2);\n            double dist = cp1.DistanceTo(cp2);\n            Assert.IsTrue(GeometRi3D.AlmostEqual(dist, 0));\n        }\n\n        [TestMethod]\n        public void TetTetDistanceTest_09()\n        {\n            // Vertex-Vertex penetration\n            Tetrahedron t1 = new Tetrahedron(new Point3d(0.01, 0, 0), new Point3d(-1, -1, -1), new Point3d(-1, -1, 1), new Point3d(-1, 1, 1));\n            Tetrahedron t2 = new Tetrahedron(new Point3d(0, 0, 0), new Point3d(1, -1, -1), new Point3d(1, -1, 1), new Point3d(1, 1, 1));\n            ConvexPolyhedron cp1 = ConvexPolyhedron.FromTetrahedron(t1);\n            ConvexPolyhedron cp2 = ConvexPolyhedron.FromTetrahedron(t2);\n            double dist = cp1.DistanceTo(cp2);\n            Assert.IsTrue(GeometRi3D.AlmostEqual(dist, 0));\n        }\n\n        [TestMethod]\n        public void TetTetDistanceTest_10()\n        {\n            // Vertex-Edge penetration\n            Tetrahedron t1 = new Tetrahedron(new Point3d(0.01, 0, 0), new Point3d(-1, -1, -1), new Point3d(-1, -1, 1), new Point3d(-1, 1, 1));\n            Tetrahedron t2 = new Tetrahedron(new Point3d(0, -1, 0), new Point3d(0, 1, 0), new Point3d(1, 0, -1), new Point3d(1, 0, 1));\n            ConvexPolyhedron cp1 = ConvexPolyhedron.FromTetrahedron(t1);\n            ConvexPolyhedron cp2 = ConvexPolyhedron.FromTetrahedron(t2);\n            double dist = cp1.DistanceTo(cp2);\n            Assert.IsTrue(GeometRi3D.AlmostEqual(dist, 0));\n        }\n\n        [TestMethod]\n        public void TetTetDistanceTest_11()\n        {\n            // Vertex-Face penetration\n            Tetrahedron t1 = new Tetrahedron(new Point3d(0.1, 0, 0), new Point3d(-1, -1, -1), new Point3d(-1, -1, 1), new Point3d(-1, 1, 1));\n            Tetrahedron t2 = new Tetrahedron(new Point3d(0, -1, -1), new Point3d(0, 1, -1), new Point3d(0, 0, 1), new Point3d(1, 0, 0));\n            ConvexPolyhedron cp1 = ConvexPolyhedron.FromTetrahedron(t1);\n            ConvexPolyhedron cp2 = ConvexPolyhedron.FromTetrahedron(t2);\n            double dist = cp1.DistanceTo(cp2);\n            Assert.IsTrue(GeometRi3D.AlmostEqual(dist, 0));\n        }\n\n        [TestMethod]\n        public void TetTetDistanceTest_12()\n        {\n            // Edge-Edge penetration\n            Tetrahedron t1 = new Tetrahedron(new Point3d(0.1, 0, -1), new Point3d(0.1, 0, 1), new Point3d(-1, -1, 0), new Point3d(-1, 1, 0));\n            Tetrahedron t2 = new Tetrahedron(new Point3d(0, -1, 0), new Point3d(0, 1, 0), new Point3d(1, 0, -1), new Point3d(1, 0, 1));\n            ConvexPolyhedron cp1 = ConvexPolyhedron.FromTetrahedron(t1);\n            ConvexPolyhedron cp2 = ConvexPolyhedron.FromTetrahedron(t2);\n            double dist = cp1.DistanceTo(cp2);\n            Assert.IsTrue(GeometRi3D.AlmostEqual(dist, 0));\n        }\n\n        #region \"Segment distance\"\n        [TestMethod]\n        public void SegmentDistanceTest_01()\n        {\n            // Segment inside CP\n            ConvexPolyhedron cp = ConvexPolyhedron.FromBox(new Box3d());\n            Segment3d s = new Segment3d(new Point3d(0.1, 0.1, 0.1), new Point3d(0.2, 0.2, 0.2));\n\n            Assert.IsTrue(cp.DistanceTo(s) == 0);\n        }\n\n        [TestMethod]\n        public void SegmentDistanceTest_02()\n        {\n            // Segment touch face\n            ConvexPolyhedron cp = ConvexPolyhedron.FromBox(new Box3d());\n            Segment3d s = new Segment3d(new Point3d(0.3, 0.3, 0.0), new Point3d(0.7, 0.7, -1));\n\n            Assert.IsTrue(GeometRi3D.AlmostEqual(cp.DistanceTo(s), 0));\n        }\n\n        [TestMethod]\n        public void SegmentDistanceTest_03()\n        {\n            // Segment outside of CP\n            ConvexPolyhedron cp = ConvexPolyhedron.FromBox(new Box3d());\n            Segment3d s = new Segment3d(new Point3d(1, 0.3, 0.3), new Point3d(2, 0.3, 0.3));\n\n            Assert.IsTrue(GeometRi3D.AlmostEqual(cp.DistanceTo(s), 0.5));\n        }\n\n        [TestMethod]\n        public void SegmentDistanceTest_04()\n        {\n            // Segment outside of CP\n            ConvexPolyhedron cp = ConvexPolyhedron.FromBox(new Box3d());\n            Segment3d s = new Segment3d(new Point3d(1, 1, 1), new Point3d(2, 2, 2));\n\n            Assert.IsTrue(GeometRi3D.AlmostEqual(cp.DistanceTo(s), Sqrt(3) * 0.5));\n        }\n        #endregion\n\n        [TestMethod]\n        public void CircleDistanceTest_01()\n        {\n            ConvexPolyhedron cp = ConvexPolyhedron.FromBox(new Box3d());\n            Circle3d s = new Circle3d(new Point3d(1.5, 1.5, 1.5), 1, new Vector3d(1, 1, 1));\n            double d = cp.DistanceTo(s);\n            Assert.IsTrue(GeometRi3D.AlmostEqual(cp.DistanceTo(s), Sqrt(3)));\n        }\n\n        [TestMethod]\n        public void ExtrudeTest_01()\n        {\n            ConvexPolyhedron cp = ConvexPolyhedron.FromBox(new Box3d());\n            ConvexPolyhedron extrude = cp.face[0].Extrude(cp.face[0].normal, 0.2);\n            Assert.IsTrue(extrude.Center == new Point3d(0.0, 0.0, -0.6));\n        }\n\n        [TestMethod]\n        public void ExtrudeTest_02()\n        {\n            ConvexPolyhedron cp = ConvexPolyhedron.FromBox(new Box3d());\n            ConvexPolyhedron extrude = cp.face[0].Extrude(cp.face[0].normal, 0.2, true);\n            Assert.IsTrue(extrude.Center == new Point3d(0.0, 0.0, -0.5));\n            Assert.IsTrue(extrude.Center == cp.face[0].Center);\n        }\n\n        [TestMethod]\n        public void PointDistanceTest_01()\n        {\n            // Point inside CP\n            ConvexPolyhedron cp = ConvexPolyhedron.FromBox(new Box3d());\n            Point3d p  = new Point3d(0.1, 0.1, 0.1);\n\n            Assert.IsTrue(cp.DistanceTo(p) == 0);\n        }\n\n        [TestMethod]\n        public void PointDistanceTest_02()\n        {\n            // Point on face\n            ConvexPolyhedron cp = ConvexPolyhedron.FromBox(new Box3d());\n            Point3d p = new Point3d(0.1, 0.1, 0.5);\n            Assert.IsTrue(cp.DistanceTo(p) == 0);\n\n            p = new Point3d(-0.1, 0.1, -0.5);\n            Assert.IsTrue(cp.DistanceTo(p) == 0);\n\n            p = new Point3d(-0.1, -0.5, -0.2);\n            Assert.IsTrue(cp.DistanceTo(p) == 0);\n        }\n\n        [TestMethod]\n        public void PointDistanceTest_03()\n        {\n            // Point on edge\n            ConvexPolyhedron cp = ConvexPolyhedron.FromBox(new Box3d());\n            Point3d p = new Point3d(0.1, 0.5, 0.5);\n            Assert.IsTrue(cp.DistanceTo(p) == 0);\n\n            p = new Point3d(-0.1, -0.5, 0.5);\n            Assert.IsTrue(cp.DistanceTo(p) == 0);\n\n            p = new Point3d(-0.5, -0.5, 0.2);\n            Assert.IsTrue(cp.DistanceTo(p) == 0);\n        }\n\n        [TestMethod]\n        public void PointDistanceTest_04()\n        {\n            // Point in vertex\n            ConvexPolyhedron cp = ConvexPolyhedron.FromBox(new Box3d());\n            Point3d p = new Point3d(0.5, -0.5, 0.5);\n            Assert.IsTrue(cp.DistanceTo(p) == 0);\n        }\n\n        [TestMethod]\n        public void PointDistanceTest_05()\n        {\n            // Point outside, projection to face\n            ConvexPolyhedron cp = ConvexPolyhedron.FromBox(new Box3d());\n            Point3d p = new Point3d(0.6, -0.1, 0.1);\n            Assert.IsTrue(Abs(cp.DistanceTo(p) - 0.1) < GeometRi3D.DefaultTolerance);\n\n            p = new Point3d(0.1, -0.1, 0.6);\n            Assert.IsTrue(Abs(cp.DistanceTo(p) - 0.1) < GeometRi3D.DefaultTolerance);\n        }\n\n        [TestMethod]\n        public void PointDistanceTest_06()\n        {\n            // Point outside\n            ConvexPolyhedron cp = ConvexPolyhedron.FromBox(new Box3d());\n            Point3d p = new Point3d(1.5, 1.5, 0.0);\n            Assert.IsTrue(Abs(cp.DistanceTo(p) - Sqrt(2.0)) < GeometRi3D.DefaultTolerance);\n\n            p = new Point3d(0.5, 1.5, -1.5);\n            Assert.IsTrue(Abs(cp.DistanceTo(p) - Sqrt(2.0)) < GeometRi3D.DefaultTolerance);\n        }\n\n        #region \"Segment intersection\"\n        [TestMethod]\n        public void SegmentPolyhedronIntersectionCheckTest_01()\n        {\n            // Segment is inside\n            Box3d box = new Box3d(new Point3d(0, 0, 0), new Point3d(1, 1, 1));\n            ConvexPolyhedron cp = ConvexPolyhedron.FromBox(box);\n            Segment3d s = new Segment3d(new Point3d(0.1, 0.1, 0.1), new Point3d(0.5, 0.5, 0.5));\n            Assert.IsTrue(cp.Intersects(s));\n        }\n\n        [TestMethod]\n        public void SegmentPolyhedronIntersectionCheckTest_02()\n        {\n            // Segment intersects face\n            Box3d box = new Box3d(new Point3d(0, 0, 0), new Point3d(1, 1, 1));\n            ConvexPolyhedron cp = ConvexPolyhedron.FromBox(box);\n            Segment3d s = new Segment3d(new Point3d(0.5, 0.5, 0.5), new Point3d(1.5, 0.5, 0.5));\n            Assert.IsTrue(cp.Intersects(s));\n        }\n\n        [TestMethod]\n        public void SegmentPolyhedronIntersectionCheckTest_03()\n        {\n            // Segment intersects edge\n            Box3d box = new Box3d(new Point3d(0, 0, 0), new Point3d(1, 1, 1));\n            ConvexPolyhedron cp = ConvexPolyhedron.FromBox(box);\n            Segment3d s = new Segment3d(new Point3d(0.5, 0.5, 0.5), new Point3d(1.5, 1.5, 0.5));\n            Assert.IsTrue(cp.Intersects(s));\n        }\n\n        [TestMethod]\n        public void SegmentPolyhedronIntersectionCheckTest_04()\n        {\n            // Segment intersects vertex\n            Box3d box = new Box3d(new Point3d(0, 0, 0), new Point3d(1, 1, 1));\n            ConvexPolyhedron cp = ConvexPolyhedron.FromBox(box);\n            Segment3d s = new Segment3d(new Point3d(0.5, 0.5, 0.5), new Point3d(1.5, 1.5, 1.5));\n            Assert.IsTrue(cp.Intersects(s));\n        }\n\n        [TestMethod]\n        public void SegmentPolyhedronIntersectionCheckTest_05()\n        {\n            // Segment end touch face\n            Box3d box = new Box3d(new Point3d(0, 0, 0), new Point3d(1, 1, 1));\n            ConvexPolyhedron cp = ConvexPolyhedron.FromBox(box);\n            Segment3d s = new Segment3d(new Point3d(1.0 - 1e-12, 0.5, 0.5), new Point3d(1.5, 0.5, 0.5));\n            Assert.IsTrue(cp.Intersects(s));\n        }\n\n        [TestMethod]\n        public void SegmentPolyhedronIntersectionCheckTest_06()\n        {\n            // Segment end touch edge\n            Box3d box = new Box3d(new Point3d(0, 0, 0), new Point3d(1, 1, 1));\n            ConvexPolyhedron cp = ConvexPolyhedron.FromBox(box);\n            Segment3d s = new Segment3d(new Point3d(1.0 - 1e-13, 1.0 - 1e-13, 0.5), new Point3d(1.5, 1.5, 0.5));\n            Assert.IsTrue(cp.Intersects(s));\n        }\n\n        [TestMethod]\n        public void SegmentPolyhedronIntersectionCheckTest_07()\n        {\n            // Segment end touch vertex\n            Box3d box = new Box3d(new Point3d(0, 0, 0), new Point3d(1, 1, 1));\n            ConvexPolyhedron cp = ConvexPolyhedron.FromBox(box);\n            Segment3d s = new Segment3d(new Point3d(1.0 - 1e-13, 1.0 - 1e-13, 1.0 - 1e-13), new Point3d(1.5, 1.5, 1.5));\n            Assert.IsTrue(cp.Intersects(s));\n        }\n\n        [TestMethod]\n        public void SegmentPolyhedronIntersectionCheckTest_08()\n        {\n            // Segment lies on face\n            Box3d box = new Box3d(new Point3d(0, 0, 0), new Point3d(1, 1, 1));\n            ConvexPolyhedron cp = ConvexPolyhedron.FromBox(box);\n            Segment3d s = new Segment3d(new Point3d(1.0 - 1e-13, 0.5, 0.5), new Point3d(1.0, 0.2, 0.2));\n            Assert.IsTrue(cp.Intersects(s));\n        }\n\n        [TestMethod]\n        public void SegmentPolyhedronIntersectionCheckTest_09()\n        {\n            // Segment lies on edge\n            Box3d box = new Box3d(new Point3d(0, 0, 0), new Point3d(1, 1, 1));\n            ConvexPolyhedron cp = ConvexPolyhedron.FromBox(box);\n            \n            // Undefined behaviour\n            Segment3d s = new Segment3d(new Point3d(1.0, 1.0, 0.5), new Point3d(1.0, 1.0, 0.8));\n            Assert.IsTrue(cp.Intersects(s));\n\n            s = new Segment3d(new Point3d(1.0, 1.0, 0.5), new Point3d(1.0, 1.0, 0.1));\n            Assert.IsFalse(cp.Intersects(s));\n        }\n\n        [TestMethod]\n        public void SegmentPolyhedronIntersectionCheckTest_10()\n        {\n            // Segment touch edge\n            Box3d box = new Box3d(new Point3d(0, 0, 0), new Point3d(1, 1, 1));\n            ConvexPolyhedron cp = ConvexPolyhedron.FromBox(box);\n            Segment3d s = new Segment3d(new Point3d(2.0 - 1e-15, 0.0, 0.5), new Point3d(0.0, 2.0, 0.5));\n            Assert.IsTrue(cp.Intersects(s));\n        }\n\n        [TestMethod]\n        public void SegmentPolyhedronIntersectionCheckTest_11()\n        {\n            // Segment outside\n            Box3d box = new Box3d(new Point3d(0, 0, 0), new Point3d(1, 1, 1));\n            ConvexPolyhedron cp = ConvexPolyhedron.FromBox(box);\n            Segment3d s = new Segment3d(new Point3d(2.0 , 0.0, 0.5), new Point3d(3.0, 2.0, 0.99));\n            Assert.IsFalse(cp.Intersects(s));\n        }\n\n        [TestMethod]\n        public void SegmentPolyhedronIntersectionCheckTest_12()\n        {\n            // Segment outside\n            Box3d box = new Box3d(new Point3d(0, 0, 0), new Point3d(1, 1, 1));\n            ConvexPolyhedron cp = ConvexPolyhedron.FromBox(box);\n            Segment3d s = new Segment3d(new Point3d(2.0, 2.0, 2.0), new Point3d(3.0, 2.0, 3.0));\n            Assert.IsFalse(cp.Intersects(s));\n        }\n\n        #endregion\n\n        #region \"Triangle intersection\"\n        [TestMethod]\n        public void TrianglePolyhedronIntersectionCheckTest_01()\n        {\n            // Triangle is inside\n            Box3d box = new Box3d(new Point3d(0, 0, 0), new Point3d(1, 1, 1));\n            ConvexPolyhedron cp = ConvexPolyhedron.FromBox(box);\n            Triangle t = new Triangle(new Point3d(0.1, 0.1, 0.1), new Point3d(0.5, 0.5, 0.5), new Point3d(0.1, 0.2, 0.3));\n            Assert.IsTrue(cp.Intersects(t));\n        }\n\n        [TestMethod]\n        public void TrianglePolyhedronIntersectionCheckTest_02()\n        {\n            // Triangle intersects face\n            Box3d box = new Box3d(new Point3d(0, 0, 0), new Point3d(1, 1, 1));\n            ConvexPolyhedron cp = ConvexPolyhedron.FromBox(box);\n            Triangle t = new Triangle(new Point3d(0.1, 0.1, 0.1), new Point3d(0.5, 0.5, 0.5), new Point3d(1.1, 0.2, 0.3));\n            Assert.IsTrue(cp.Intersects(t));\n        }\n\n        [TestMethod]\n        public void TrianglePolyhedronIntersectionCheckTest_03()\n        {\n            // Triangle intersects edge\n            Box3d box = new Box3d(new Point3d(0, 0, 0), new Point3d(1, 1, 1));\n            ConvexPolyhedron cp = ConvexPolyhedron.FromBox(box);\n            Triangle t = new Triangle(new Point3d(0.5, 0.5, 0.5), new Point3d(1.5, 1.5, 0.1), new Point3d(1.5, 1.5, 0.7));\n            Assert.IsTrue(cp.Intersects(t));\n        }\n\n        [TestMethod]\n        public void TrianglePolyhedronIntersectionCheckTest_04()\n        {\n            // Triangle touch edge\n            Box3d box = new Box3d(new Point3d(0, 0, 0), new Point3d(1, 1, 1));\n            ConvexPolyhedron cp = ConvexPolyhedron.FromBox(box);\n            Triangle t = new Triangle(new Point3d(1.0 - 1e-13, 1.0 - 1e-13, 0.5), new Point3d(1.5, 1.5, 0.7), new Point3d(1.5, 1.5, 0.1));\n            Assert.IsTrue(cp.Intersects(t));\n        }\n\n        [TestMethod]\n        public void TrianglePolyhedronIntersectionCheckTest_05()\n        {\n            // Triangle outside\n            Box3d box = new Box3d(new Point3d(0, 0, 0), new Point3d(1, 1, 1));\n            ConvexPolyhedron cp = ConvexPolyhedron.FromBox(box);\n            Triangle t = new Triangle(new Point3d(1.1, 1.1, 0.5), new Point3d(1.5, 1.5, 0.7), new Point3d(1.5, 1.5, 0.1));\n            Assert.IsFalse(cp.Intersects(t));\n        }\n\n        #endregion\n\n    }\n}\n"
  },
  {
    "path": "GeometRi.Tests/CoordTransformTest.cs",
    "content": "﻿using System;\nusing static System.Math;\nusing Microsoft.VisualStudio.TestTools.UnitTesting;\nusing GeometRi;\n\nnamespace GeometRi_Tests\n{\n    [TestClass]\n    public class CoordTransformTest\n    {\n        //===============================================================\n        // Coordinate transformation tests\n        //===============================================================\n\n        [TestMethod()]\n        public void PointConvertToTest()\n        {\n            Coord3d coord1 = Coord3d.GlobalCS.Copy();\n            Coord3d coord2 = Coord3d.GlobalCS.Copy();\n            coord2.RotateDeg(new Vector3d(1, 1, 1), 120);\n\n            Assert.IsTrue(new Point3d(1, 2, 3, coord1) == new Point3d(2, 3, 1, coord2));\n        }\n\n        [TestMethod()]\n        public void PointConvertToTest2()\n        {\n            Coord3d coord1 = new Coord3d(new Point3d(2, 3, 1), Matrix3d.RotationMatrix(new Vector3d(2, 1, 5), PI / 3));\n            Coord3d coord2 = new Coord3d(new Point3d(1, -3, 4), Matrix3d.RotationMatrix(new Vector3d(3, 2, 1), PI / 2));\n\n            Point3d p1 = new Point3d(1, 2, -2, coord1);\n            Point3d p2 = p1.ConvertTo(coord2);\n\n            Assert.IsTrue(p2 == p1);\n        }\n\n        [TestMethod()]\n        public void PointConvertToGlobalTest()\n        {\n            Coord3d coord1 = Coord3d.GlobalCS.Copy();\n            Coord3d coord2 = Coord3d.GlobalCS.Copy();\n            coord2.RotateDeg(new Vector3d(1, 1, 1), 120);\n\n            Point3d p1 = new Point3d(1, 2, 3, coord1);\n            Point3d p2 = new Point3d(2, 3, 1, coord2);\n            p1 = p1.ConvertToGlobal();\n            p2 = p2.ConvertToGlobal();\n\n            Assert.IsTrue(p1 == p2);\n        }\n\n        [TestMethod()]\n        public void VectorConvertToTest()\n        {\n            Coord3d coord1 = Coord3d.GlobalCS.Copy();\n            Coord3d coord2 = Coord3d.GlobalCS.Copy();\n            coord2.RotateDeg(new Vector3d(1, 1, 1), 120);\n\n            Assert.IsTrue(new Vector3d(1, 2, 3, coord1) == new Vector3d(2, 3, 1, coord2));\n        }\n\n        [TestMethod()]\n        public void VectorConvertToTest2()\n        {\n            Coord3d coord1 = Coord3d.GlobalCS.Copy();\n            Coord3d coord2 = Coord3d.GlobalCS.Copy();\n            coord2.RotateDeg(new Vector3d(1, 1, 1), 120);\n\n            Vector3d v1 = new Vector3d(2, 3, 4);\n            Vector3d v2 = v1.ConvertTo(coord1);\n            Vector3d v3 = v1.ConvertTo(coord2);\n\n            Assert.IsTrue(v2 == v3);\n        }\n\n        [TestMethod()]\n        public void LineConvertToTest()\n        {\n            Coord3d coord1 = Coord3d.GlobalCS.Copy();\n            Coord3d coord2 = Coord3d.GlobalCS.Copy();\n            coord2.RotateDeg(new Vector3d(1, 1, 1), 120);\n\n            Point3d p1 = new Point3d(1, 2, 3, coord1);\n            Vector3d v1 = new Vector3d(0, 0, 1);\n            Line3d l1 = new Line3d(p1, v1);\n            l1.Point = l1.Point.ConvertTo(coord2);\n            Plane3d s1 = coord2.XZ_plane;\n            s1.Point = s1.Point.ConvertTo(coord1);\n\n            Assert.IsTrue((Point3d)l1.IntersectionWith(s1) == new Point3d(1, 2, 0));\n        }\n\n        [TestMethod()]\n        public void PlaneConvertToTest()\n        {\n            Coord3d coord1 = Coord3d.GlobalCS.Copy();\n            Coord3d coord2 = Coord3d.GlobalCS.Copy();\n            coord2.RotateDeg(new Vector3d(1, 1, 1), 120);\n\n            Point3d p1 = new Point3d(1, 2, 3, coord1);\n            Vector3d v1 = new Vector3d(0, 0, 1);\n            Line3d l1 = new Line3d(p1, v1);\n            l1.Point = l1.Point.ConvertTo(coord2);\n            Plane3d s1 = coord2.XZ_plane;\n            s1.Point = s1.Point.ConvertTo(coord1);\n\n            Assert.IsTrue((Point3d)s1.IntersectionWith(l1) == new Point3d(1, 2, 0));\n        }\n\n        [TestMethod()]\n        public void LineConvertProjectionToPlaneTest()\n        {\n            Coord3d coord1 = Coord3d.GlobalCS.Copy();\n            Coord3d coord2 = Coord3d.GlobalCS.Copy();\n            coord2.RotateDeg(new Vector3d(1, 1, 1), 120);\n\n            Point3d p1 = new Point3d(1, 2, 3, coord1);\n            Vector3d v1 = new Vector3d(0, 0, 1);\n            Line3d l1 = new Line3d(p1, v1);\n            l1.Point = l1.Point.ConvertTo(coord2);\n            Plane3d s1 = coord2.XZ_plane;\n            s1.Point = s1.Point.ConvertTo(coord1);\n\n            Assert.IsTrue((Point3d)l1.ProjectionTo(s1) == new Point3d(1, 2, 0));\n        }\n\n        [TestMethod()]\n        public void LineConvertProjectionToPlaneTest2()\n        {\n            Coord3d coord1 = Coord3d.GlobalCS.Copy();\n            Coord3d coord2 = Coord3d.GlobalCS.Copy();\n            coord2.RotateDeg(new Vector3d(1, 1, 1), 120);\n\n            Point3d p1 = new Point3d(1, 2, 3, coord1);\n            Vector3d v1 = new Vector3d(0, 2, 1);\n            Line3d l1 = new Line3d(p1, v1);\n            l1.Point = l1.Point.ConvertTo(coord2);\n            Plane3d s1 = coord2.XZ_plane;\n            s1.Point = s1.Point.ConvertTo(coord1);\n\n            Assert.IsTrue((Line3d)l1.ProjectionTo(s1) == new Line3d(new Point3d(1, 2, 0), new Vector3d(0, 1, 0)));\n        }\n\n        [TestMethod()]\n        public void PlaneConvertIntersectionToPlaneTest()\n        {\n            Coord3d coord1 = Coord3d.GlobalCS.Copy();\n            Coord3d coord2 = Coord3d.GlobalCS.Copy();\n            coord1.RotateDeg(new Vector3d(1, 1, 1), 90);\n            coord2.RotateDeg(new Vector3d(1, 1, 1), 120);\n\n\n            Plane3d s1 = new Plane3d(1, 1, 1, 0, Coord3d.GlobalCS);\n            Plane3d s2 = new Plane3d(1, 3, 6, 0, coord1);\n            Plane3d s3 = new Plane3d(100, -1000, 1, 0, coord2);\n\n\n            Assert.IsTrue((Point3d)s1.IntersectionWith(s2, s3) == new Point3d(0, 0, 0));\n        }\n\n        [TestMethod()]\n        public void PlaneConvertToGlobalTest()\n        {\n            Coord3d coord1 = Coord3d.GlobalCS.Copy();\n            Coord3d coord2 = Coord3d.GlobalCS.Copy();\n            coord1.RotateDeg(new Vector3d(1, 1, 1), 90);\n            coord2.RotateDeg(new Vector3d(1, 1, 1), 120);\n            coord1.Origin = new Point3d(1, 1, 1);\n            coord2.Origin = new Point3d(10, 2, 5);\n\n            Plane3d s1 = new Plane3d(1, 1, 1, 0, Coord3d.GlobalCS);\n            s1.Point = s1.Point.ConvertTo(coord1);\n            s1.Point = s1.Point.ConvertTo(coord2);\n            s1.Point = s1.Point.ConvertToGlobal();\n\n            Assert.IsTrue(s1 == new Plane3d(1, 1, 1, 0, Coord3d.GlobalCS));\n        }\n\n        [TestMethod()]\n        public void PlaneIntersectionWithPlanesTest()\n        {\n            Coord3d coord1 = Coord3d.GlobalCS.Copy();\n            Coord3d coord2 = Coord3d.GlobalCS.Copy();\n            coord1.RotateDeg(new Vector3d(1, 2, 3), 90);\n            coord2.RotateDeg(new Vector3d(1, 1, 1), 120);\n            coord1.Origin = new Point3d(1, 1, 1);\n            coord2.Origin = new Point3d(10, 2, 5);\n\n            Plane3d s1 = new Plane3d(1, 1, 1, 0, Coord3d.GlobalCS);\n            Plane3d s2 = new Plane3d(3, -2, 0, 9, Coord3d.GlobalCS);\n            Plane3d s3 = new Plane3d(2, 5, 1, -2, Coord3d.GlobalCS);\n            Point3d p1 = (Point3d)s1.IntersectionWith(s2, s3);\n            s1.Point = s1.Point.ConvertTo(coord2);\n            s2.Normal = s2.Normal.ConvertTo(coord1).ConvertTo(coord2);\n            s3.Point = s3.Point.ConvertTo(coord2).ConvertTo(coord1);\n            Point3d p2 = (Point3d)s2.IntersectionWith(s1, s3);\n\n            Assert.IsTrue(p1 == p2);\n        }\n\n    }\n}\n"
  },
  {
    "path": "GeometRi.Tests/CoplanarityTest.cs",
    "content": "﻿using System;\nusing static System.Math;\nusing Microsoft.VisualStudio.TestTools.UnitTesting;\nusing GeometRi;\n\nnamespace GeometRi_Tests\n{\n    [TestClass]\n    public class CoplanarityTest\n    {\n        [TestMethod]\n        public void PlanarObjectsCoplanarityTest()\n        {\n            Plane3d s1 = new Plane3d(new Point3d(1, 1, 1), new Vector3d(1, 0, 0));\n            Plane3d s2 = new Plane3d(new Point3d(-1, 1, 1), new Vector3d(1, 0, 0));\n            Plane3d s3 = new Plane3d(new Point3d(1, 2, 3), new Vector3d(-1, 0, 0));\n            Plane3d s4 = new Plane3d(new Point3d(1, 1, 1), new Vector3d(-1, 2, 3));\n\n            Assert.IsTrue(s1.IsCoplanarTo(s3));\n            Assert.IsTrue(s1.IsCoplanarTo(s1));\n            Assert.IsFalse(s1.IsCoplanarTo(s2));\n            Assert.IsFalse(s1.IsCoplanarTo(s4));\n\n            Circle3d c = new Circle3d(new Point3d(1, 2, 2), 5, new Vector3d(1, 0, 0));\n            Assert.IsTrue(c.IsCoplanarTo(c));\n            Assert.IsTrue(s1.IsCoplanarTo(c));\n            Assert.IsFalse(s2.IsCoplanarTo(c));\n            Assert.IsTrue(c.IsCoplanarTo(s1));\n            Assert.IsFalse(c.IsCoplanarTo(s2));\n\n            Triangle t = new Triangle(new Point3d(1, 2, 2), new Point3d(1, -5, 0), new Point3d(1, 3, -2));\n            Assert.IsTrue(t.IsCoplanarTo(t));\n            Assert.IsTrue(s1.IsCoplanarTo(t));\n            Assert.IsFalse(s2.IsCoplanarTo(t));\n            Assert.IsTrue(t.IsCoplanarTo(s1));\n            Assert.IsFalse(t.IsCoplanarTo(s2));\n            Assert.IsTrue(t.IsCoplanarTo(c));\n        }\n\n        [TestMethod]\n        public void LinearObjectsCoplanarityTest()\n        {\n            Line3d l1 = new Line3d(new Point3d(1, 1, 1), new Vector3d(0, 1, 1));\n            Line3d l2 = new Line3d(new Point3d(-1, 2, 1), new Vector3d(0, 1, 1));\n            Line3d l3 = new Line3d(new Point3d(1, 2, 3), new Vector3d(0, 2, 1));\n            Line3d l4 = new Line3d(new Point3d(1, 1, 1), new Vector3d(1, 2, 3));\n\n            // Self-coplanarity\n            Assert.IsTrue(l1.IsCoplanarTo(l1));\n            // Parallel lines\n            Assert.IsTrue(l1.IsCoplanarTo(l2));\n            // Intersecting lines\n            Assert.IsTrue(l1.IsCoplanarTo(l3));\n            // Intersecting lines\n            Assert.IsTrue(l1.IsCoplanarTo(l4));\n            // Not coplanar\n            Assert.IsFalse(l3.IsCoplanarTo(l4));\n\n            Segment3d s1 = new Segment3d(new Point3d(1, 2, 4), new Point3d(1, -2, 5));\n            Assert.IsTrue(s1.IsCoplanarTo(s1));\n            Assert.IsTrue(s1.IsCoplanarTo(l1));\n            Assert.IsFalse(s1.IsCoplanarTo(l4));\n        }\n\n        [TestMethod]\n        public void PlanarLinearObjectsCoplanarityTest()\n        {\n            Plane3d p1 = new Plane3d(new Point3d(1, 1, 1), new Vector3d(1, 0, 0));\n            Line3d l1 = new Line3d(new Point3d(1, 1, 1), new Vector3d(0, 1, 1));\n            Segment3d s1 = new Segment3d(new Point3d(1, 2, 4), new Point3d(2, -2, 0));\n\n            Assert.IsTrue(p1.IsCoplanarTo(l1));\n            Assert.IsTrue(l1.IsCoplanarTo(p1));\n            Assert.IsFalse(p1.IsCoplanarTo(s1));\n            Assert.IsFalse(s1.IsCoplanarTo(p1));\n\n        }\n    }\n}\n"
  },
  {
    "path": "GeometRi.Tests/EllipseTest.cs",
    "content": "﻿using System;\nusing static System.Math;\nusing Microsoft.VisualStudio.TestTools.UnitTesting;\nusing GeometRi;\n\nnamespace GeometRi_Tests\n{\n    [TestClass]\n    public class EllipseTest\n    {\n        //===============================================================\n        // Ellipse tests\n        //===============================================================\n\n        [TestMethod()]\n        public void PointBelongsToEllipseTest()\n        {\n            Vector3d v1 = new Vector3d(3, 0, 1);\n            Vector3d v2 = 3 * v1.OrthogonalVector;\n            Ellipse e = new Ellipse(new Point3d(5, 6, 1), v1, v2);\n            Assert.IsTrue(e.ParametricForm(0.5).BelongsTo(e));\n        }\n\n        [TestMethod()]\n        public void EllipseProjectionToPlaneTest()\n        {\n            Vector3d v1 = new Vector3d(3, 0, 1);\n            Vector3d v2 = 3 * v1.OrthogonalVector;\n            Ellipse e = new Ellipse(new Point3d(5, 6, 1), v1, v2);\n            Plane3d s = new Plane3d(5, 2, 3, -3);\n\n            Point3d p = e.ParametricForm(0.5).ProjectionTo(s);\n            Assert.IsTrue(p.BelongsTo(e.ProjectionTo(s)));\n            p = e.ParametricForm(0.725).ProjectionTo(s);\n            Assert.IsTrue(p.BelongsTo(e.ProjectionTo(s)));\n            p = e.ParametricForm(2.7122).ProjectionTo(s);\n            Assert.IsTrue(p.BelongsTo(e.ProjectionTo(s)));\n        }\n\n        [TestMethod()]\n        public void EllipseIntersectionWithLineTest()\n        {\n            Point3d p = new Point3d(0, 0, 0);\n            Vector3d v1 = new Vector3d(3, 0, 0);\n            Vector3d v2 = new Vector3d(0, 2, 0);\n            Ellipse e = new Ellipse(p, v1, v2);\n\n            Line3d l = new Line3d(new Point3d(0, -2, 0), new Vector3d(1, 2, 0));\n            Segment3d res = new Segment3d(new Point3d(0, -2, 0), new Point3d(9.0/5.0, 8.0/5.0, 0));\n            Assert.AreEqual((Segment3d)e.IntersectionWith(l), res);\n\n            l = new Line3d(new Point3d(0, -2, 0), new Vector3d(1, 0, 0));\n            Assert.AreEqual((Point3d)e.IntersectionWith(l), new Point3d(0, -2, 0));\n        }\n\n        [TestMethod()]\n        public void EllipseIntersectionWithPlaneTest()\n        {\n            Point3d p = new Point3d(0, 0, 0);\n            Vector3d v1 = new Vector3d(4, 0, 0);\n            Vector3d v2 = new Vector3d(0, 6, 0);\n            Ellipse e = new Ellipse(p, v1, v2);\n\n            p = new Point3d(0, 50, 0);\n            v1 = new Vector3d(-1000, 1, 0);\n            Plane3d s = new Plane3d(p, v1);\n\n            Segment3d res = new Segment3d(new Point3d(-0.0440003630169716, 5.99963698302842, 0), new Point3d(-0.0559994119835347, -5.99941198353467, 0));\n            Assert.AreEqual(e.IntersectionWith(s), res);\n        }\n\n        [TestMethod]\n        public void PointInEllipseTest()\n        {\n            Point3d p = new Point3d(1, 1, 0);\n            Ellipse s = new Ellipse(p, new Vector3d(10, 0, 0), new Vector3d(0, 5, 0));\n\n            p = new Point3d(2, 2, 0);  // Point inside\n            Assert.IsTrue(p.BelongsTo(s));\n            Assert.IsTrue(p.IsInside(s));\n            Assert.IsFalse(p.IsOutside(s));\n            Assert.IsFalse(p.IsOnBoundary(s));\n\n            p = new Point3d(1, 6, 0);  // Point on boundary\n            Assert.IsTrue(p.BelongsTo(s));\n            Assert.IsFalse(p.IsInside(s));\n            Assert.IsFalse(p.IsOutside(s));\n            Assert.IsTrue(p.IsOnBoundary(s));\n\n            p = new Point3d(1, 6.005, 0);  // Point outside\n            Assert.IsFalse(p.BelongsTo(s));\n            Assert.IsFalse(p.IsInside(s));\n            Assert.IsTrue(p.IsOutside(s));\n            Assert.IsFalse(p.IsOnBoundary(s));\n\n            p = new Point3d(1, 2, 0.01);  // Point outside\n            Assert.IsFalse(p.BelongsTo(s));\n            Assert.IsFalse(p.IsInside(s));\n            Assert.IsTrue(p.IsOutside(s));\n            Assert.IsFalse(p.IsOnBoundary(s));\n        }\n\n        [TestMethod]\n        public void PointInEllipseRelativeTest()\n        {\n            Point3d p = new Point3d(1, 1, 0);\n            Ellipse s = new Ellipse(p, new Vector3d(10, 0, 0), new Vector3d(0, 5, 0));\n\n            double tol = GeometRi3D.Tolerance;\n            bool mode = GeometRi3D.UseAbsoluteTolerance;\n            GeometRi3D.Tolerance = 0.01;\n            GeometRi3D.UseAbsoluteTolerance = false;\n\n            p = new Point3d(2, 2, 0.1);  // Point inside\n            Assert.IsTrue(p.BelongsTo(s));\n            Assert.IsTrue(p.IsInside(s));\n            Assert.IsFalse(p.IsOutside(s));\n            Assert.IsFalse(p.IsOnBoundary(s));\n\n            p = new Point3d(1, 6, 0);  // Point on boundary\n            Assert.IsTrue(p.BelongsTo(s));\n            Assert.IsFalse(p.IsInside(s));\n            Assert.IsFalse(p.IsOutside(s));\n            Assert.IsTrue(p.IsOnBoundary(s));\n\n            p = new Point3d(1, 6.2, 0);  // Point outside\n            Assert.IsFalse(p.BelongsTo(s));\n            Assert.IsFalse(p.IsInside(s));\n            Assert.IsTrue(p.IsOutside(s));\n            Assert.IsFalse(p.IsOnBoundary(s));\n\n            p = new Point3d(1, 2, 0.2);  // Point outside\n            Assert.IsFalse(p.BelongsTo(s));\n            Assert.IsFalse(p.IsInside(s));\n            Assert.IsTrue(p.IsOutside(s));\n            Assert.IsFalse(p.IsOnBoundary(s));\n\n            // Resore initial state\n            GeometRi3D.UseAbsoluteTolerance = mode;\n            GeometRi3D.Tolerance = tol;\n        }\n\n        [TestMethod()]\n        public void ClosestPointTest()\n        {\n            Point3d p = new Point3d(0, 0, 0);\n            Vector3d v1 = new Vector3d(10, 0, 0);\n            Vector3d v2 = new Vector3d(0, 5, 0);\n            Ellipse e = new Ellipse(p, v1, v2);\n\n            p = new Point3d(11, 0, 0);\n            Assert.AreEqual(e.ClosestPoint(p), new Point3d(10, 0, 0));\n\n            p = new Point3d(-11, 0, 0);\n            Assert.AreEqual(e.ClosestPoint(p), new Point3d(-10, 0, 0));\n\n            p = new Point3d(0, 6, 0);\n            Assert.AreEqual(e.ClosestPoint(p), new Point3d(0, 5, 0));\n\n            p = new Point3d(0, -6, 0);\n            Assert.AreEqual(e.ClosestPoint(p), new Point3d(0, -5, 0));\n\n            p = new Point3d(0, 0, 0);\n            Assert.AreEqual(e.ClosestPoint(p), new Point3d(0, 5, 0));\n\n            p = new Point3d(0, 0, 0);\n            v1 = new Vector3d(10, 0, 0);\n            v2 = new Vector3d(0, 10, 0);\n            e = new Ellipse(p, v1, v2);\n\n            p = new Point3d(11, 11, 0);\n            Assert.AreEqual(e.ClosestPoint(p), new Point3d(Sqrt(50), Sqrt(50), 0));\n\n            p = new Point3d(-11, 11, 0);\n            Assert.AreEqual(e.ClosestPoint(p), new Point3d(-Sqrt(50), Sqrt(50), 0));\n\n            p = new Point3d(-11, -11, 0);\n            Assert.AreEqual(e.ClosestPoint(p), new Point3d(-Sqrt(50), -Sqrt(50), 0));\n        }\n    }\n}\n"
  },
  {
    "path": "GeometRi.Tests/EllipsoidTest.cs",
    "content": "﻿using System;\nusing static System.Math;\nusing Microsoft.VisualStudio.TestTools.UnitTesting;\nusing GeometRi;\n\nnamespace GeometRi_Tests\n{\n    [TestClass]\n    public class EllipsoidTest\n    {\n        [TestMethod()]\n        public void EllipsoidIntersectionWithLineTest()\n        {\n            Point3d p = new Point3d(0, 0, 0);\n            Vector3d v1 = new Vector3d(4, 0, 0);\n            Vector3d v2 = new Vector3d(0, 6, 0);\n            Vector3d v3 = new Vector3d(0, 0, 9);\n            Ellipsoid e = new Ellipsoid(p, v1, v2, v3);\n\n\n            Line3d l = new Line3d(new Point3d(0, 0, 0), v1 = new Vector3d(1, 0, 0));\n            Assert.IsTrue((Segment3d)e.IntersectionWith(l) == new Segment3d(new Point3d(-4, 0, 0), new Point3d(4, 0, 0)));\n\n            l = new Line3d(new Point3d(0, 0, 0), v1 = new Vector3d(0, 1, 0));\n            Assert.IsTrue((Segment3d)e.IntersectionWith(l) == new Segment3d(new Point3d(0, -6, 0), new Point3d(0, 6, 0)));\n\n            l = new Line3d(new Point3d(0, 0, 0), v1 = new Vector3d(0, 0, 1));\n            Assert.IsTrue((Segment3d)e.IntersectionWith(l) == new Segment3d(new Point3d(0, 0, -9), new Point3d(0, 0, 9)));\n\n\n            p = new Point3d(0, 2, 1);\n            v1 = new Vector3d(-1, 1, 3);\n            l = new Line3d(p, v1);\n\n            Segment3d s = (Segment3d)e.IntersectionWith(l);\n\n            Assert.IsTrue(s.P1.IsOnBoundary(e));\n            Assert.IsTrue(s.P2.IsOnBoundary(e));\n\n        }\n\n        [TestMethod()]\n        public void EllipsoidIntersectionWithSegmentRelativeTest()\n        {\n            double tol = GeometRi3D.Tolerance;\n            bool mode = GeometRi3D.UseAbsoluteTolerance;\n            GeometRi3D.Tolerance = 0.01;\n            GeometRi3D.UseAbsoluteTolerance = false;\n\n            Point3d p = new Point3d(0, 0, 0);\n            Vector3d v1 = new Vector3d(4, 0, 0);\n            Vector3d v2 = new Vector3d(0, 6, 0);\n            Vector3d v3 = new Vector3d(0, 0, 9);\n            Ellipsoid e = new Ellipsoid(p, v1, v2, v3);\n\n            Segment3d s = new Segment3d(new Point3d(-5, 0.01, 0), new Point3d(5, 0, 0));\n            Assert.IsTrue((Segment3d)e.IntersectionWith(s) == new Segment3d(new Point3d(-4, 0, 0), new Point3d(4, 0, 0)));\n\n            s = new Segment3d(new Point3d(0, -7, 0), new Point3d(0.01, 7, 0));\n            Assert.IsTrue((Segment3d)e.IntersectionWith(s) == new Segment3d(new Point3d(0, -6, 0), new Point3d(0, 6, 0)));\n\n            s = new Segment3d(new Point3d(0, 0, 0), new Point3d(0.01, 0, 10));\n            Assert.IsTrue((Segment3d)e.IntersectionWith(s) == new Segment3d(new Point3d(0, 0, 0), new Point3d(0, 0, 9)));\n\n            // Resore initial state\n            GeometRi3D.UseAbsoluteTolerance = mode;\n            GeometRi3D.Tolerance = tol;\n        }\n\n        [TestMethod()]\n        public void EllipsoidIntersectionWithPlaneTest()\n        {\n            Point3d p = new Point3d(0, 0, 0);\n            Vector3d v1 = new Vector3d(5, 0, 0);\n            Vector3d v2 = new Vector3d(0, 4, 0);\n            Vector3d v3 = new Vector3d(0, 0, 3);\n            Ellipsoid e = new Ellipsoid(p, v1, v2, v3);\n\n            Plane3d s = new Plane3d(1, 2, 3, 4);\n\n            Ellipse res = (Ellipse)e.IntersectionWith(s);\n\n            Assert.IsTrue(res.Center.IsInside(e));\n            Assert.IsTrue(res.Center.Translate(res.MajorSemiaxis).BelongsTo(e));\n            Assert.IsTrue(res.Center.Translate(res.MinorSemiaxis).BelongsTo(e));\n            Assert.IsTrue(res.Center.Translate(-res.MajorSemiaxis).BelongsTo(e));\n            Assert.IsTrue(res.Center.Translate(-res.MinorSemiaxis).BelongsTo(e));\n            Assert.IsTrue(res.ParametricForm(0.01).BelongsTo(e));\n            Assert.IsTrue(res.ParametricForm(0.11).BelongsTo(e));\n            Assert.IsTrue(res.ParametricForm(0.55).BelongsTo(e));\n            Assert.IsTrue(res.ParametricForm(0.876).BelongsTo(e));\n        }\n\n        [TestMethod()]\n        public void EllipsoidProjectionToLineTest_1()\n        {\n            Point3d p = new Point3d(0, 0, 0);\n            Vector3d v1 = new Vector3d(4, 0, 0);\n            Vector3d v2 = new Vector3d(0, 6, 0);\n            Vector3d v3 = new Vector3d(0, 0, 9);\n            Ellipsoid e = new Ellipsoid(p, v1, v2, v3);\n\n            p = new Point3d(1, 1, 1);\n            v1 = new Vector3d(0, 1, 0);\n            Line3d l = new Line3d(p, v1);\n            Segment3d s = e.ProjectionTo(l);\n\n            Segment3d res = new Segment3d(new Point3d(1, 6, 1), new Point3d(1, -6, 1));\n\n            Assert.AreEqual(s,res);\n        }\n\n        [TestMethod()]\n        public void EllipsoidProjectionToLineTest_2()\n        {\n            Point3d p = new Point3d(0, 0, 0);\n            Vector3d v1 = new Vector3d(4, 0, 0);\n            Vector3d v2 = new Vector3d(0, 6, 0);\n            Vector3d v3 = new Vector3d(0, 0, 9);\n            Ellipsoid e = new Ellipsoid(p, v1, v2, v3);\n\n            p = new Point3d(1, 1, 1);\n            v1 = new Vector3d(1, 1, 3);\n            Line3d l = new Line3d(p, v1);\n            Segment3d s = e.ProjectionTo(l);\n\n            // Construct plane orthogonal to line and passing through segment end point\n            // And check if it is touching ellipsoid\n            Plane3d pl1 = new Plane3d(s.P1, v1);\n            object obj = e.IntersectionWith(pl1);\n\n            if (obj.GetType() == typeof(Point3d))\n            {\n                p = (Point3d)obj;\n                if (p.BelongsTo(e)) {\n                    Assert.IsTrue(true);\n                }\n                else\n                {\n                    Assert.Fail();\n                }\n            }\n            else\n            {\n                Assert.Fail();\n            }\n\n        }\n\n        [TestMethod]\n        public void PointInEllipsoidTest()\n        {\n            Point3d p = new Point3d(1, 1, 1);\n            Ellipsoid s = new Ellipsoid(p, new Vector3d(3,0,0), new Vector3d(0, 5, 0), new Vector3d(0, 0, 2));\n\n            p = new Point3d(2, 2, 2);  // Point inside\n            Assert.IsTrue(p.BelongsTo(s));\n            Assert.IsTrue(p.IsInside(s));\n            Assert.IsFalse(p.IsOutside(s));\n            Assert.IsFalse(p.IsOnBoundary(s));\n\n            p = new Point3d(1, 6, 1);  // Point on surface\n            Assert.IsTrue(p.BelongsTo(s));\n            Assert.IsFalse(p.IsInside(s));\n            Assert.IsFalse(p.IsOutside(s));\n            Assert.IsTrue(p.IsOnBoundary(s));\n\n            p = new Point3d(1, 6.005, 1);  // Point outside\n            Assert.IsFalse(p.BelongsTo(s));\n            Assert.IsFalse(p.IsInside(s));\n            Assert.IsTrue(p.IsOutside(s));\n            Assert.IsFalse(p.IsOnBoundary(s));\n        }\n\n        [TestMethod()]\n        public void ClosestPointTest()\n        {\n            Point3d p = new Point3d(0, 0, 0);\n            Vector3d v1 = new Vector3d(10, 0, 0);\n            Vector3d v2 = new Vector3d(0, 5, 0);\n            Vector3d v3 = new Vector3d(0, 0, 3);\n            Ellipsoid e = new Ellipsoid(p, v1, v2, v3);\n\n            p = new Point3d(11, 0, 0);\n            Assert.AreEqual(e.ClosestPoint(p), new Point3d(10, 0, 0));\n\n            p = new Point3d(-11, 0, 0);\n            Assert.AreEqual(e.ClosestPoint(p), new Point3d(-10, 0, 0));\n\n            p = new Point3d(0, 6, 0);\n            Assert.AreEqual(e.ClosestPoint(p), new Point3d(0, 5, 0));\n\n            p = new Point3d(0, -6, 0);\n            Assert.AreEqual(e.ClosestPoint(p), new Point3d(0, -5, 0));\n\n            p = new Point3d(0, 0, 0);\n            Assert.AreEqual(e.ClosestPoint(p), new Point3d(0, 3, 0));\n\n            p = new Point3d(0, 0, 0);\n            v1 = new Vector3d(10, 0, 0);\n            v2 = new Vector3d(0, 10, 0);\n            v3 = new Vector3d(0, 0, 10);\n            e = new Ellipsoid(p, v1, v2, v3);\n\n            p = new Point3d(11, 11, 0);\n            Assert.AreEqual(e.ClosestPoint(p), new Point3d(Sqrt(50), Sqrt(50), 0));\n\n            p = new Point3d(-11, 11, 0);\n            Assert.AreEqual(e.ClosestPoint(p), new Point3d(-Sqrt(50), Sqrt(50), 0));\n\n            p = new Point3d(-11, -11, 0);\n            Assert.AreEqual(e.ClosestPoint(p), new Point3d(-Sqrt(50), -Sqrt(50), 0));\n\n            p = new Point3d(-6, -6, 6);\n            double dist = Sqrt(3 * 6 * 6) - 10;\n            Assert.IsTrue(Abs(e.ClosestPoint(p).DistanceTo(p) - dist) <= GeometRi3D.Tolerance);\n\n            // Internal point\n            p = new Point3d(-5, -5, 5);\n            dist = Abs(Sqrt(3 * 5 * 5) - 10);\n            Assert.IsTrue(Abs(e.ClosestPoint(p).DistanceTo(p) - dist) <= GeometRi3D.Tolerance);\n        }\n\n        [TestMethod()]\n        public void IntersectsEllipsoidSphere_01()\n        {\n            // Separate\n            Ellipsoid A = new Ellipsoid(new Point3d(0, 0, 0), new Vector3d(2, 0, 0), new Vector3d(0, 1, 0), new Vector3d(0, 0, 1));\n            Sphere B = new Sphere(new Point3d(3.000000000001, 0, 0), 1);\n            Assert.AreEqual(A.IntersectionCheck(B, GeometRi3D.DefaultTolerance), 1);\n\n            B = new Sphere(new Point3d(-3.000000000001, 0, 0), 1);\n            Assert.AreEqual(A.IntersectionCheck(B, GeometRi3D.DefaultTolerance), 1);\n\n            B = new Sphere(new Point3d(0, 2.00001, 0), 1);\n            Assert.AreEqual(A.IntersectionCheck(B, GeometRi3D.DefaultTolerance), 1);\n\n            B = new Sphere(new Point3d(0, -2.00001, 0), 1);\n            Assert.AreEqual(A.IntersectionCheck(B, GeometRi3D.DefaultTolerance), 1);\n        }\n\n        [TestMethod()]\n        public void IntersectsEllipsoidSphere_02()\n        {\n            // Externaly touch\n            Ellipsoid A = new Ellipsoid(new Point3d(0, 0, 0), new Vector3d(2, 0, 0), new Vector3d(0, 1, 0), new Vector3d(0, 0, 1));\n            Sphere B = new Sphere(new Point3d(3.0, 0, 0), 1);\n            Assert.AreEqual(A.IntersectionCheck(B, GeometRi3D.DefaultTolerance), 0);\n\n            B = new Sphere(new Point3d(-3.0, 0, 0), 1);\n            Assert.AreEqual(A.IntersectionCheck(B, GeometRi3D.DefaultTolerance), 0);\n\n            B = new Sphere(new Point3d(0, 2.0, 0), 1);\n            Assert.AreEqual(A.IntersectionCheck(B, GeometRi3D.DefaultTolerance), 0);\n\n            B = new Sphere(new Point3d(0, -2.0, 0), 1);\n            Assert.AreEqual(A.IntersectionCheck(B, GeometRi3D.DefaultTolerance), 0);\n        }\n\n        [TestMethod()]\n        public void IntersectsEllipsoidSphere_03()\n        {\n            // Overlap\n            Ellipsoid A = new Ellipsoid(new Point3d(0, 0, 0), new Vector3d(2, 0, 0), new Vector3d(0, 1, 0), new Vector3d(0, 0, 1));\n            Sphere B = new Sphere(new Point3d(2.999, 0, 0), 1);\n            Assert.AreEqual(A.IntersectionCheck(B, GeometRi3D.DefaultTolerance), -1);\n\n            B = new Sphere(new Point3d(-2.999, 0, 0), 1);\n            Assert.AreEqual(A.IntersectionCheck(B, GeometRi3D.DefaultTolerance), -1);\n\n            B = new Sphere(new Point3d(0, 1.999, 0), 1);\n            Assert.AreEqual(A.IntersectionCheck(B, GeometRi3D.DefaultTolerance), -1);\n\n            B = new Sphere(new Point3d(0, -1.999, 0), 1);\n            Assert.AreEqual(A.IntersectionCheck(B, GeometRi3D.DefaultTolerance), -1);\n        }\n\n        //[TestMethod()]\n        //public void IntersectsTwoEllipsoids_01()\n        //{\n        //    // Separate\n        //    Ellipsoid A = new Ellipsoid(new Point3d(0, 0, 0), new Vector3d(2, 0, 0), new Vector3d(0, 1, 0), new Vector3d(0, 0, 1));\n        //    Ellipsoid B = new Ellipsoid(new Point3d(3.001, 0, 0), new Vector3d(1, 0, 0), new Vector3d(0, 2, 0), new Vector3d(0, 0, 3));\n        //    Assert.AreEqual(A.IntersectionCheck(B, GeometRi3D.DefaultTolerance), 1);\n\n        //    B = new Ellipsoid(new Point3d(-3.000001, 0, 0), new Vector3d(1, 0, 0), new Vector3d(0, 3, 0), new Vector3d(0, 0, 3));\n        //    Assert.AreEqual(A.IntersectionCheck(B, GeometRi3D.DefaultTolerance), 1);\n\n        //    B = new Ellipsoid(new Point3d(0, 2.0001, 0), new Vector3d(1, 0, 0), new Vector3d(0, 1, 0), new Vector3d(0, 0, 3));\n        //    Assert.AreEqual(A.IntersectionCheck(B, GeometRi3D.DefaultTolerance), 1);\n\n        //    B = new Ellipsoid(new Point3d(0, -2.00001, 0), new Vector3d(1, 0, 1), new Vector3d(0, 1, 0), new Vector3d(-2, 0, 2));\n        //    Assert.AreEqual(A.IntersectionCheck(B, GeometRi3D.DefaultTolerance), 1);\n\n        //    A = new Ellipsoid(new Point3d(0, 0, 0), new Vector3d(2, 0, 2), new Vector3d(0, 1, 0), new Vector3d(-1, 0, 1));\n        //    B = new Ellipsoid(new Point3d(0, 2.001, 0), new Vector3d(1, 0, 1), new Vector3d(0, 1, 0), new Vector3d(-3, 0, 3));\n        //    Assert.AreEqual(A.IntersectionCheck(B, GeometRi3D.DefaultTolerance), 1);\n        //}\n\n        //[TestMethod()]\n        //public void IntersectsTwoEllipsoids_02()\n        //{\n        //    // Externaly touch\n        //    Ellipsoid A = new Ellipsoid(new Point3d(0, 0, 0), new Vector3d(2, 0, 0), new Vector3d(0, 1, 0), new Vector3d(0, 0, 1));\n        //    Ellipsoid B = new Ellipsoid(new Point3d(3.0, 0, 0), new Vector3d(1, 0, 0), new Vector3d(0, 2, 0), new Vector3d(0, 0, 3));\n        //    Assert.AreEqual(A.IntersectionCheck(B, GeometRi3D.DefaultTolerance), 0);\n\n        //    B = new Ellipsoid(new Point3d(-3.0, 0, 0), new Vector3d(1, 0, 0), new Vector3d(0, 3, 0), new Vector3d(0, 0, 3));\n        //    Assert.AreEqual(A.IntersectionCheck(B, GeometRi3D.DefaultTolerance), 0);\n\n        //    B = new Ellipsoid(new Point3d(0, 2.0, 0), new Vector3d(1, 0, 0), new Vector3d(0, 1, 0), new Vector3d(0, 0, 3));\n        //    Assert.AreEqual(A.IntersectionCheck(B, GeometRi3D.DefaultTolerance), 0);\n\n        //    B = new Ellipsoid(new Point3d(0, -2.0, 0), new Vector3d(1, 0, 1), new Vector3d(0, 1, 0), new Vector3d(-2, 0, 2));\n        //    Assert.AreEqual(A.IntersectionCheck(B, GeometRi3D.DefaultTolerance), 0);\n\n        //    A = new Ellipsoid(new Point3d(0, 0, 0), new Vector3d(2, 0, 2), new Vector3d(0, 1, 0), new Vector3d(-1, 0, 1));\n        //    B = new Ellipsoid(new Point3d(0, 2.0, 0), new Vector3d(1, 0, 1), new Vector3d(0, 1, 0), new Vector3d(-3, 0, 3));\n        //    Assert.AreEqual(A.IntersectionCheck(B, GeometRi3D.DefaultTolerance), 0);\n        //}\n\n        //[TestMethod()]\n        //public void IntersectsTwoEllipsoids_03()\n        //{\n        //    // Overlap\n        //    Ellipsoid A = new Ellipsoid(new Point3d(0, 0, 0), new Vector3d(2, 0, 0), new Vector3d(0, 1, 0), new Vector3d(0, 0, 1));\n        //    Ellipsoid B = new Ellipsoid(new Point3d(2.99, 0, 0), new Vector3d(1, 0, 0), new Vector3d(0, 2, 0), new Vector3d(0, 0, 3));\n        //    Assert.AreEqual(A.IntersectionCheck(B, GeometRi3D.DefaultTolerance), -1);\n\n        //    B = new Ellipsoid(new Point3d(-2.99, 0, 0), new Vector3d(1, 0, 0), new Vector3d(0, 3, 0), new Vector3d(0, 0, 3));\n        //    Assert.AreEqual(A.IntersectionCheck(B, GeometRi3D.DefaultTolerance), -1);\n\n        //    B = new Ellipsoid(new Point3d(0, 1.99, 0), new Vector3d(1, 0, 0), new Vector3d(0, 1, 0), new Vector3d(0, 0, 3));\n        //    Assert.AreEqual(A.IntersectionCheck(B, GeometRi3D.DefaultTolerance), -1);\n\n        //    B = new Ellipsoid(new Point3d(0, -1.99, 0), new Vector3d(1, 0, 1), new Vector3d(0, 1, 0), new Vector3d(-2, 0, 2));\n        //    Assert.AreEqual(A.IntersectionCheck(B, GeometRi3D.DefaultTolerance), -1);\n\n        //    A = new Ellipsoid(new Point3d(0, 0, 0), new Vector3d(2, 0, 2), new Vector3d(0, 1, 0), new Vector3d(-1, 0, 1));\n        //    B = new Ellipsoid(new Point3d(0, 1.99, 0), new Vector3d(1, 0, 1), new Vector3d(0, 1, 0), new Vector3d(-3, 0, 3));\n        //    Assert.AreEqual(A.IntersectionCheck(B, GeometRi3D.DefaultTolerance), -1);\n        //}\n\n    }\n}\n"
  },
  {
    "path": "GeometRi.Tests/GeometRi.Tests.csproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"15.0\" DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <Import Project=\"..\\packages\\MSTest.TestAdapter.1.1.11\\build\\net45\\MSTest.TestAdapter.props\" Condition=\"Exists('..\\packages\\MSTest.TestAdapter.1.1.11\\build\\net45\\MSTest.TestAdapter.props')\" />\n  <PropertyGroup>\n    <Configuration Condition=\" '$(Configuration)' == '' \">Debug</Configuration>\n    <Platform Condition=\" '$(Platform)' == '' \">AnyCPU</Platform>\n    <ProjectGuid>{B99F3733-D205-4EDA-9B4C-F2F68A9DFD59}</ProjectGuid>\n    <OutputType>Library</OutputType>\n    <AppDesignerFolder>Properties</AppDesignerFolder>\n    <RootNamespace>GeometRi.Tests</RootNamespace>\n    <AssemblyName>GeometRi.Tests</AssemblyName>\n    <TargetFrameworkVersion>v4.8</TargetFrameworkVersion>\n    <FileAlignment>512</FileAlignment>\n    <ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>\n    <VisualStudioVersion Condition=\"'$(VisualStudioVersion)' == ''\">15.0</VisualStudioVersion>\n    <VSToolsPath Condition=\"'$(VSToolsPath)' == ''\">$(MSBuildExtensionsPath32)\\Microsoft\\VisualStudio\\v$(VisualStudioVersion)</VSToolsPath>\n    <ReferencePath>$(ProgramFiles)\\Common Files\\microsoft shared\\VSTT\\$(VisualStudioVersion)\\UITestExtensionPackages</ReferencePath>\n    <IsCodedUITest>False</IsCodedUITest>\n    <TestProjectType>UnitTest</TestProjectType>\n    <NuGetPackageImportStamp>\n    </NuGetPackageImportStamp>\n    <TargetFrameworkProfile />\n  </PropertyGroup>\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' \">\n    <DebugSymbols>true</DebugSymbols>\n    <DebugType>full</DebugType>\n    <Optimize>false</Optimize>\n    <OutputPath>bin\\Debug\\</OutputPath>\n    <DefineConstants>DEBUG;TRACE</DefineConstants>\n    <ErrorReport>prompt</ErrorReport>\n    <WarningLevel>4</WarningLevel>\n    <Prefer32Bit>false</Prefer32Bit>\n  </PropertyGroup>\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' \">\n    <DebugType>pdbonly</DebugType>\n    <Optimize>true</Optimize>\n    <OutputPath>bin\\Release\\</OutputPath>\n    <DefineConstants>TRACE</DefineConstants>\n    <ErrorReport>prompt</ErrorReport>\n    <WarningLevel>4</WarningLevel>\n    <Prefer32Bit>false</Prefer32Bit>\n  </PropertyGroup>\n  <ItemGroup>\n    <Reference Include=\"GeometRi, Version=1.5.0.8, Culture=neutral, processorArchitecture=MSIL\">\n      <SpecificVersion>False</SpecificVersion>\n      <HintPath>..\\GeometRi\\bin\\Debug\\net461\\GeometRi.dll</HintPath>\n    </Reference>\n    <Reference Include=\"Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL\">\n      <Private>False</Private>\n    </Reference>\n    <Reference Include=\"System\" />\n    <Reference Include=\"System.Core\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Compile Include=\"Point3dTest.cs\" />\n    <Compile Include=\"Properties\\AssemblyInfo.cs\" />\n    <Compile Include=\"Line3dTest.cs\" />\n    <Compile Include=\"Ray3dTest.cs\" />\n    <Compile Include=\"Segment3dTest.cs\" />\n    <Compile Include=\"Plane3dTest.cs\" />\n    <Compile Include=\"Matrix3dTest.cs\" />\n    <Compile Include=\"OtherTest.cs\" />\n    <Compile Include=\"CoordTransformTest.cs\" />\n    <Compile Include=\"TranslateTest.cs\" />\n    <Compile Include=\"RotateTest.cs\" />\n    <Compile Include=\"ReflectTest.cs\" />\n    <Compile Include=\"SphereTest.cs\" />\n    <Compile Include=\"CircleTest.cs\" />\n    <Compile Include=\"EllipseTest.cs\" />\n    <Compile Include=\"TriangleTest.cs\" />\n    <Compile Include=\"EllipsoidTest.cs\" />\n    <Compile Include=\"RotationTest.cs\" />\n    <Compile Include=\"Box3dTest.cs\" />\n    <Compile Include=\"QuaternionTest.cs\" />\n    <Compile Include=\"BoundingBoxTest.cs\" />\n    <Compile Include=\"RelativeToleranceTest.cs\" />\n    <Compile Include=\"CoplanarityTest.cs\" />\n    <Compile Include=\"TetrahedronTest.cs\" />\n    <Compile Include=\"NormalizeTest.cs\" />\n    <Compile Include=\"ConvexPolyhedronTest.cs\" />\n    <Compile Include=\"AABBTest.cs\" />\n    <Compile Include=\"Vector3dTest.cs\" />\n    <Compile Include=\"TriangleIntersectionWithLineSegmentTests.cs\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"packages.config\" />\n  </ItemGroup>\n  <Import Project=\"$(VSToolsPath)\\TeamTest\\Microsoft.TestTools.targets\" Condition=\"Exists('$(VSToolsPath)\\TeamTest\\Microsoft.TestTools.targets')\" />\n  <Import Project=\"$(MSBuildToolsPath)\\Microsoft.CSharp.targets\" />\n  <Target Name=\"EnsureNuGetPackageBuildImports\" BeforeTargets=\"PrepareForBuild\">\n    <PropertyGroup>\n      <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>\n    </PropertyGroup>\n    <Error Condition=\"!Exists('..\\packages\\MSTest.TestAdapter.1.1.11\\build\\net45\\MSTest.TestAdapter.props')\" Text=\"$([System.String]::Format('$(ErrorText)', '..\\packages\\MSTest.TestAdapter.1.1.11\\build\\net45\\MSTest.TestAdapter.props'))\" />\n    <Error Condition=\"!Exists('..\\packages\\MSTest.TestAdapter.1.1.11\\build\\net45\\MSTest.TestAdapter.targets')\" Text=\"$([System.String]::Format('$(ErrorText)', '..\\packages\\MSTest.TestAdapter.1.1.11\\build\\net45\\MSTest.TestAdapter.targets'))\" />\n  </Target>\n  <Import Project=\"..\\packages\\MSTest.TestAdapter.1.1.11\\build\\net45\\MSTest.TestAdapter.targets\" Condition=\"Exists('..\\packages\\MSTest.TestAdapter.1.1.11\\build\\net45\\MSTest.TestAdapter.targets')\" />\n</Project>"
  },
  {
    "path": "GeometRi.Tests/Line3DTest.cs",
    "content": "﻿using System;\nusing static System.Math;\nusing Microsoft.VisualStudio.TestTools.UnitTesting;\nusing GeometRi;\n\nnamespace GeometRi_Tests\n{\n    [TestClass]\n    public class Line3dTest\n    {\n        //===============================================================\n        // Line3d tests\n        //===============================================================\n\n        [TestMethod()]\n        public void LineDistanceToCrossingLineTest()\n        {\n            Point3d p2 = new Point3d(1, -5, -1);\n            Vector3d v2 = new Vector3d(-2, 3, 4);\n            Line3d l1 = new Line3d(p2, v2);\n            p2 = new Point3d(-2, 1, 2);\n            v2 = new Vector3d(-2, 2, 3);\n            Line3d l2 = new Line3d(p2, v2);\n            dynamic zzz = l1.DistanceTo(l2);\n            Assert.IsTrue(Abs(l1.DistanceTo(l2) - 3) < GeometRi3D.Tolerance);\n        }\n\n        [TestMethod()]\n        public void LineDistanceToParallelLineTest()\n        {\n            Point3d p2 = new Point3d(1, -5, -1);\n            Vector3d v2 = new Vector3d(-2, 3, 4);\n            Line3d l1 = new Line3d(p2, v2);\n            p2 = new Point3d(-4, 3, 5);\n            v2 = new Vector3d(4, -6, -8);\n            Line3d l2 = new Line3d(p2, v2);\n            Assert.IsTrue(Abs(l1.DistanceTo(l2) - 3) < GeometRi3D.Tolerance);\n        }\n\n        [TestMethod()]\n        public void LinePerpendicularToLineTest()\n        {\n            Point3d p1 = new Point3d(1, -5, -1);\n            Vector3d v1 = new Vector3d(-2, 3, 4);\n            Line3d l1 = new Line3d(p1, v1);\n\n            Point3d p2 = new Point3d(-2, 1, 2);\n            Vector3d v2 = new Vector3d(-2, 2, 3);\n            Line3d l2 = new Line3d(p2, v2);\n\n            Assert.IsTrue(l1.PerpendicularTo(l2) == new Point3d(-4, 3, 5));\n        }\n\n        [TestMethod()]\n        public void LineIntersectionWithLineTest()\n        {\n            Line3d l1 = new Line3d(new Point3d(), new Vector3d(1, 0, 0));\n            Line3d l2 = new Line3d(new Point3d(8,0,0), new Vector3d(-5, 0, 0));\n            Assert.IsTrue((Line3d)l1.IntersectionWith(l2) == l1);\n\n            l2 = new Line3d(new Point3d(5, 5, 0), new Vector3d(1, -1, 0));\n            Assert.IsTrue((Point3d)l1.IntersectionWith(l2) == new Point3d(10,0,0));\n\n            l2 = new Line3d(new Point3d(5, 5, 1), new Vector3d(1, -1, 0));\n            Assert.IsTrue((Object)l1.IntersectionWith(l2) == null);\n\n        }\n\n        [TestMethod()]\n        public void LineIntersectionWithPlaneTest()\n        {\n            Point3d p1 = new Point3d(1, -5, -1);\n            Vector3d v1 = new Vector3d(-2, 3, 4);\n            Line3d l1 = new Line3d(p1, v1);\n            Plane3d s1 = new Plane3d(-2, 2, 3, -29);\n\n            Assert.IsTrue((Point3d)l1.IntersectionWith(s1) == new Point3d(-3, 1, 7));\n        }\n\n        [TestMethod()]\n        public void LineIntersectionWithPlaneTest2()\n        {\n            // Parallel line\n            Point3d p1 = new Point3d(1, 0, 0);\n            Vector3d v1 = new Vector3d(1, 1, 1);\n            Plane3d s1 = new Plane3d(p1, v1);\n            p1 = new Point3d(0, 2, 0);\n            Point3d p2 = new Point3d(0, 0, 2);\n            Line3d l1 = new Line3d(p1, new Vector3d(p1, p2));\n\n            Assert.IsTrue(l1.IntersectionWith(s1) == null);\n        }\n\n        [TestMethod()]\n        public void LineIntersectionWithPlaneTest3()\n        {\n            // Line lies in the plane\n            Point3d p1 = new Point3d(1, 0, 0);\n            Vector3d v1 = new Vector3d(1, 1, 1);\n            Plane3d s1 = new Plane3d(p1, v1);\n            p1 = new Point3d(0, 1, 0);\n            Point3d p2 = new Point3d(0, 0, 1);\n            Line3d l1 = new Line3d(p1, new Vector3d(p1, p2));\n\n            Assert.IsTrue((Line3d)l1.IntersectionWith(s1) == l1);\n        }\n\n        [TestMethod()]\n        public void LineProjectionToPlaneTest()\n        {\n            Point3d p1 = new Point3d(1, -5, -1);\n            Vector3d v1 = new Vector3d(-2, 3, 4);\n            Line3d l1 = new Line3d(p1, v1);\n            Plane3d s1 = new Plane3d(-2, 2, 3, -29);\n\n            Point3d p2 = (Point3d)l1.IntersectionWith(s1);\n            Line3d l2 = (Line3d)l1.ProjectionTo(s1);\n\n            Assert.IsTrue(p2.BelongsTo(l2));\n        }\n    }\n}\n"
  },
  {
    "path": "GeometRi.Tests/Matrix3dTest.cs",
    "content": "﻿using System;\nusing static System.Math;\nusing Microsoft.VisualStudio.TestTools.UnitTesting;\nusing GeometRi;\n\nnamespace GeometRi_Tests\n{\n    [TestClass]\n    public class Matrix3dTest\n    {\n        //===============================================================\n        // Matrix3d tests\n        //===============================================================\n\n        [TestMethod()]\n        public void MatrixDeterminantTest()\n        {\n            Matrix3d m = new Matrix3d(new[] { 1.0, 2.0, 3.0 }, new[] { 0.0, -4.0, 1.0 }, new[] { 0.0, 3.0, -1.0 });\n            Assert.IsTrue(Abs(m.Det - 1) < GeometRi3D.Tolerance);\n        }\n\n        [TestMethod()]\n        public void MatrixInverseTest()\n        {\n            Matrix3d m = new Matrix3d(new[] { 1.0, 2.0, 3.0 }, new[] { 0.0, -4.0, 1.0 }, new[] { 0.0, 3.0, -1.0 });\n            Assert.IsTrue(m.Inverse() * m == Matrix3d.Identity());\n        }\n\n        [TestMethod()]\n        public void RotationMatrixOrthogonalityTest()\n        {\n            Matrix3d r = Matrix3d.RotationMatrix(new Vector3d(1, 2, 3), PI / 2);\n            Assert.IsTrue(r.Transpose() * r == Matrix3d.Identity());\n        }\n\n        [TestMethod()]\n        public void MatrixMaxNormTest()\n        {\n            Matrix3d m = new Matrix3d(new[] { 1.0, 2.0, 3.0 }, new[] { 0.0, -4.0, 1.0 }, new[] { 0.0, 3.0, -1.0 });\n            Assert.IsTrue(Abs(m.MaxNorm - 4) < GeometRi3D.Tolerance);\n        }\n\n    }\n}\n"
  },
  {
    "path": "GeometRi.Tests/NormalizeTest.cs",
    "content": "﻿using System;\nusing static System.Math;\nusing Microsoft.VisualStudio.TestTools.UnitTesting;\nusing GeometRi;\n\nnamespace GeometRi_Tests\n{\n    [TestClass]\n    public class TestHighNumberTolerances\n    {\n        [TestMethod]\n        public void testTriangleIntersection()\n        {\n\n            GeometRi3D.UseAbsoluteTolerance = false;\n            Point3d a = new Point3d(18508, 7020, 3193);\n            Point3d b = new Point3d(-925, -162, -233);\n            Point3d c = new Point3d(-858, -349, -221);\n\n            Triangle t = new Triangle(a, b, c);\n\n            Plane3d plane = new Plane3d(new Point3d(0, 200, 0), new Vector3d(0, 1, 0));\n\n            Segment3d s0 = new Segment3d(a, b);\n            Segment3d s1 = new Segment3d(a, c);\n\n\n            object result = t.IntersectionWith(plane); //while we expect a segment3d, it can be null, or point3d like here\n\n            object inter1 = s0.IntersectionWith(plane); //returns Point3d\n            object inter2 = s1.IntersectionWith(plane);//returns another distinct Point3d \n            Segment3d expectedResult = new Segment3d((Point3d)inter1, (Point3d)inter2); //segment3d with a >0 length\n\n            Assert.IsTrue(expectedResult.Equals(result)); //Error\n        }\n\n        [TestMethod]\n        public void testCoplanar()\n        {\n            Point3d a = new Point3d(-1000, 180, -70);\n            Point3d b = new Point3d(20000, 180, -70);\n            Point3d c = new Point3d(20000, 180, 70);\n            Point3d d = new Point3d(-1000, 180, 70);\n\n            Triangle t0 = new Triangle(a, b, c);\n            Triangle t1 = new Triangle(b, c, d);\n\n            Rotation rz = new Rotation(Coord3d.GlobalCS.Zaxis, 30 * System.Math.PI / 180);\n            Rotation ry = new Rotation(Coord3d.GlobalCS.Yaxis, 10 * System.Math.PI / 180);\n\n            Point3d p = new Point3d(0, 0, 0);\n\n            t0 = t0.Rotate(rz, p);\n            t1 = t1.Rotate(rz, p);\n            t0 = t0.Rotate(ry, p);\n            t1 = t1.Rotate(ry, p);\n\n            bool areEqual = t0.ToPlane.Equals(t1.ToPlane); //returns false (expected true)\n            bool areCoplanar = t0.IsCoplanarTo(t1);//returns false (expected true)\n            Assert.IsTrue(areEqual); //Error\n            Assert.IsTrue(areCoplanar); //Error\n\n            //bool areEqual_fix = Equals_fix(t0.ToPlane,t1.ToPlane); //returns true\n            //bool areCoplanar_fix = IsCoplanarTo_fix(t0,t1); //returns true\n        }\n\n        [TestMethod]\n        public void SimpleAngleTest()\n        {\n            Point3d p0 = new Point3d(0, 0, 0, Coord3d.GlobalCS);\n            Point3d p1 = new Point3d(1, 1, 0, Coord3d.GlobalCS);\n\n            Segment3d s0 = new Segment3d(p0, p1);\n\n            double angle = s0.AngleToDeg(Coord3d.GlobalCS.Zaxis);\n            Assert.AreEqual(90, angle);\n\n            angle = s0.AngleToDeg(Coord3d.GlobalCS.Yaxis);\n            Assert.IsTrue(Abs(45 - angle) < 1e-14); //error, angle is 0, expected 45\n        }\n\n        [TestMethod]\n        public void SimpleAngleTest2()\n        {\n            Point3d p0 = new Point3d(0, 100, 0);\n            Point3d p1 = new Point3d(0, 100, -100);\n\n            Rotation r = new Rotation(Coord3d.GlobalCS.Yaxis, 30 * Math.PI / 180);\n            p1 = p1.Rotate(r, p0);\n\n            Segment3d s = new Segment3d(p0, p1);\n            double angle = s.AngleToDeg(Coord3d.GlobalCS.Zaxis);\n            Assert.IsTrue(Abs(30 - angle) < 1e-12);\n\n            angle = s.AngleToDeg(Coord3d.GlobalCS.Zaxis.Mult(-80)); \n            Assert.IsTrue(Abs(30 - angle) < 1e-12);\n \n        }\n\n        //public static bool Equals_fix(this Plane3d p0, Plane3d p1)\n        //{\n        //    bool isCoplanar;\n        //    if (p1.Normal.IsParallelTo(p0.Normal))\n        //    {\n        //        if (p1.Point.Equals(p0.Point))\n        //            isCoplanar = true;\n        //        else\n        //        {\n        //            var v = new Vector3d(p1.Point, p0.Point).Normalized;\n        //            double a = v.Dot(p0.Normal.Normalized);\n        //            isCoplanar = a <= GeometRi3D.DefaultTolerance;\n        //        }\n        //    }\n        //    else\n        //        isCoplanar = false;\n        //    return isCoplanar;\n        //}\n\n        //public static bool IsCoplanarTo_fix(this IPlanarObject p1, IPlanarObject p2)\n        //{\n        //    return Equals_fix(p1.ToPlane, p2.ToPlane);\n        //}\n    }\n}\n"
  },
  {
    "path": "GeometRi.Tests/OtherTest.cs",
    "content": "﻿using System;\nusing static System.Math;\nusing Microsoft.VisualStudio.TestTools.UnitTesting;\nusing GeometRi;\n\nnamespace GeometRi_Tests\n{\n    [TestClass]\n    public class OtherTest\n    {\n        //===============================================================\n        // Other tests\n        //===============================================================\n\n        [TestMethod()]\n        public void ToleranceTest()\n        {\n            Plane3d s1 = new Plane3d(new Point3d(0, 0, 1), new Vector3d(0, 1, 1));\n            Plane3d s2 = new Plane3d(-5, 2, 4, 1);\n            Plane3d s3 = new Plane3d(2, -3, 2, 4);\n            Assert.IsTrue((Point3d)s1.IntersectionWith(s2, s3) == (Point3d)s1.IntersectionWith((Line3d)s2.IntersectionWith(s3)));\n            GeometRi3D.Tolerance = 0;\n            Assert.IsFalse((Point3d)s1.IntersectionWith(s2, s3) == (Point3d)s1.IntersectionWith((Line3d)s2.IntersectionWith(s3)));\n            GeometRi3D.Tolerance = 1E-12;\n        }\n\n        [TestMethod()]\n        public void CoordSystemTest()\n        {\n            Coord3d c1 = new Coord3d(new Point3d(), new[] { 2.0, 0.0, 0.0 }, new[] { 1.0, 1.0, 0.0 });\n            Assert.IsTrue(c1.Axes == Matrix3d.Identity());\n\n            c1 = new Coord3d(new Point3d(), new Vector3d(2, 0, 0), new Vector3d(0, 0, 5));\n            c1.RotateDeg(new Vector3d(1, 0, 0), -90);\n            Assert.IsTrue(c1.Axes == Matrix3d.Identity());\n        }\n\n        [TestMethod()]\n        public void IsParallelToTest()\n        {\n            Vector3d v = new Vector3d(1, 0, 0);\n            Line3d l = new Line3d(new Point3d(), v);\n            Ray3d r = new Ray3d(new Point3d(), v.OrthogonalVector);\n            Circle3d c = new Circle3d(new Point3d(), 5, v);\n\n            Assert.IsTrue(v.IsParallelTo(l));\n            Assert.IsTrue(l.IsNotParallelTo(r));\n            Assert.IsTrue(r.IsOrthogonalTo(v));\n            Assert.IsTrue(c.IsOrthogonalTo(l));\n            Assert.IsTrue(r.IsParallelTo(c));\n            Assert.IsTrue(c.IsParallelTo(Coord3d.GlobalCS.YZ_plane));\n            Assert.IsTrue(c.IsOrthogonalTo(Coord3d.GlobalCS.XZ_plane));\n            Assert.IsTrue(Coord3d.GlobalCS.YZ_plane.IsOrthogonalTo(v));\n        }\n\n        [TestMethod()]\n        public void AngleToTest()\n        {\n            // Larger tolerance value is needed for these tests\n            double def_tol = GeometRi3D.Tolerance;\n            GeometRi3D.Tolerance = 1e-7;\n\n            Vector3d v = new Vector3d(-1, 1, 0);\n            Line3d l = new Line3d(new Point3d(), -v);\n            Ray3d r = new Ray3d(new Point3d(), v.OrthogonalVector);\n            Circle3d c = new Circle3d(new Point3d(), 5, v);\n\n            Assert.IsTrue(Abs(l.AngleTo(v)) <= GeometRi3D.Tolerance);\n            Assert.IsTrue(Abs(r.AngleTo(l) - PI / 2) <= GeometRi3D.Tolerance);\n            Assert.IsTrue(Abs(c.AngleTo(v) - PI / 2) <= GeometRi3D.Tolerance);\n\n            GeometRi3D.Tolerance = def_tol;\n        }\n    }\n}\n"
  },
  {
    "path": "GeometRi.Tests/Plane3dTest.cs",
    "content": "﻿using System;\nusing static System.Math;\nusing Microsoft.VisualStudio.TestTools.UnitTesting;\nusing GeometRi;\n\nnamespace GeometRi_Tests\n{\n    [TestClass]\n    public class Plane3dTest\n    {\n        //===============================================================\n        // Plane3d tests\n        //===============================================================\n\n        [TestMethod()]\n        public void PlaneIntersectionWithLineTest()\n        {\n            // Inclined line\n            Point3d p1 = new Point3d(1, -5, -1);\n            Vector3d v1 = new Vector3d(-2, 3, 4);\n            Line3d l1 = new Line3d(p1, v1);\n            Plane3d s1 = new Plane3d(-2, 2, 3, -29);\n\n            Assert.IsTrue((Point3d)s1.IntersectionWith(l1) == new Point3d(-3, 1, 7));\n        }\n\n        [TestMethod()]\n        public void PlaneIntersectionWithLineTest2()\n        {\n            // Parallel line\n            Point3d p1 = new Point3d(1, 0, 0);\n            Vector3d v1 = new Vector3d(1, 1, 1);\n            Plane3d s1 = new Plane3d(p1, v1);\n            p1 = new Point3d(0, 2, 0);\n            Point3d p2 = new Point3d(0, 0, 2);\n            Line3d l1 = new Line3d(p1, new Vector3d(p1, p2));\n\n            Assert.IsTrue(s1.IntersectionWith(l1) == null);\n        }\n\n        [TestMethod()]\n        public void PlaneIntersectionWithLineTest3()\n        {\n            // Line lies in the plane\n            Point3d p1 = new Point3d(1, 0, 0);\n            Vector3d v1 = new Vector3d(1, 1, 1);\n            Plane3d s1 = new Plane3d(p1, v1);\n            p1 = new Point3d(0, 1, 0);\n            Point3d p2 = new Point3d(0, 0, 1);\n            Line3d l1 = new Line3d(p1, new Vector3d(p1, p2));\n\n            Assert.IsTrue((Line3d)s1.IntersectionWith(l1) == l1);\n        }\n\n        //===============================================================\n        // Intersection of three planes\n        //===============================================================\n\n        [TestMethod()]\n        public void PlaneIntersectionWithTwoPlanesTest1()\n        {\n            // Three coplanar planes\n            // Planes do not coincide\n            Plane3d s1 = new Plane3d(new Point3d(0, 0, 1), new Vector3d(1, 1, 1));\n            Plane3d s2 = new Plane3d(new Point3d(2, 0, 1), new Vector3d(1, 1, 1));\n            Plane3d s3 = new Plane3d(new Point3d(0, 3, 1), new Vector3d(-1, -1, -1));\n\n            Assert.IsTrue(s1.IntersectionWith(s2, s3) == null);\n        }\n\n        [TestMethod()]\n        public void PlaneIntersectionWithTwoPlanesTest2()\n        {\n            // Three coplanar planes\n            // Two planes are coincide\n            Plane3d s1 = new Plane3d(new Point3d(0, 0, 1), new Vector3d(1, 1, 1));\n            Plane3d s2 = new Plane3d(new Point3d(2, 0, 1), new Vector3d(1, 1, 1));\n            Plane3d s3 = new Plane3d(new Point3d(1, 0, 0), new Vector3d(-1, -1, -1));\n\n            Assert.IsTrue(s1.IntersectionWith(s2, s3) == null);\n        }\n\n        [TestMethod()]\n        public void PlaneIntersectionWithTwoPlanesTest3()\n        {\n            // Three coplanar planes\n            // Three planes are coincide\n            Plane3d s1 = new Plane3d(new Point3d(0, 0, 1), new Vector3d(1, 1, 1));\n            Plane3d s2 = new Plane3d(new Point3d(0, 1, 0), new Vector3d(1, 1, 1));\n            Plane3d s3 = new Plane3d(new Point3d(1, 0, 0), new Vector3d(-1, -1, -1));\n\n            Assert.IsTrue((Plane3d)s1.IntersectionWith(s2, s3) == s1);\n        }\n\n        [TestMethod()]\n        public void PlaneIntersectionWithTwoPlanesTest4()\n        {\n            // Three vertical planes (relative to the XY-plane) with common line\n            Plane3d s1 = new Plane3d(new Point3d(0, 0, 0), new Vector3d(1, 1, 0));\n            Plane3d s2 = new Plane3d(new Point3d(0, 0, 2), new Vector3d(4, 2, 0));\n            Plane3d s3 = new Plane3d(new Point3d(0, 0, 4), new Vector3d(-1, 1, 0));\n\n            object obj = s1.IntersectionWith(s2, s3);\n\n            if (obj != null && obj.GetType() == typeof(Line3d))\n            {\n                Line3d l1 = (Line3d)obj;\n                Assert.IsTrue(l1 == new Line3d(new Point3d(0, 0, 0), new Vector3d(0, 0, 1)));\n            }\n            else\n            {\n                Assert.Fail();\n            }\n        }\n\n        [TestMethod()]\n        public void PlaneIntersectionWithTwoPlanesTest5()\n        {\n            // Three vertical planes (relative to the XY-plane) with NO common line\n            Plane3d s1 = new Plane3d(new Point3d(1, 0, 0), new Vector3d(1, 1, 0));\n            Plane3d s2 = new Plane3d(new Point3d(0, 2, 2), new Vector3d(4, 2, 0));\n            Plane3d s3 = new Plane3d(new Point3d(3, 3, 4), new Vector3d(-1, 1, 0));\n\n            object obj = s1.IntersectionWith(s2, s3);\n\n            Assert.IsTrue(obj == null);\n        }\n\n        [TestMethod()]\n        public void PlaneIntersectionWithTwoPlanesTest6()\n        {\n            // Three intersecting planes with common point\n            Plane3d s1 = new Plane3d(new Point3d(1, 0, 0), new Vector3d(0, 1, 5));\n            Plane3d s2 = new Plane3d(new Point3d(0, 2, 0), new Vector3d(4, 0, 0));\n            Plane3d s3 = new Plane3d(new Point3d(0, 0, 0), new Vector3d(-1, 1, 3));\n\n            object obj = s1.IntersectionWith(s2, s3);\n\n            if (obj != null && obj.GetType() == typeof(Point3d))\n            {\n                Point3d p1 = (Point3d)obj;\n                Assert.IsTrue(p1 == new Point3d(0, 0, 0));\n            }\n            else\n            {\n                Assert.Fail();\n            }\n        }\n\n        [TestMethod()]\n        public void PlaneIntersectionWithTwoPlanesTest()\n        {\n            Plane3d s1 = new Plane3d(new Point3d(0, 0, 1), new Vector3d(0, 1, 1));\n            Plane3d s2 = new Plane3d(-5, 2, 4, 1);\n            Plane3d s3 = new Plane3d(2, -3, 2, 4);\n            Assert.IsTrue((Point3d)s1.IntersectionWith(s2, s3) == (Point3d)s1.IntersectionWith((Line3d)s2.IntersectionWith(s3)));\n        }\n\n        //===============================================================\n\n        [TestMethod()]\n        public void PlaneEqualsToPlaneTest()\n        {\n            Point3d p1 = new Point3d(1, 0, 0);\n            Vector3d v1 = new Vector3d(1, 1, 1);\n            Plane3d s1 = new Plane3d(p1, v1);\n\n            Point3d p2 = new Point3d(0, 0, 1);\n            Vector3d v2 = new Vector3d(-1, -1, -1);\n            Plane3d s2 = new Plane3d(p2, v2);\n\n            Assert.IsTrue(s1 == s2);\n        }\n\n        [TestMethod()]\n        public void PlaneAngleToPlaneTest()\n        {\n            Point3d p1 = new Point3d(1, 0, 0);\n            Vector3d v1 = new Vector3d(0, 1, 1);\n            Plane3d s1 = new Plane3d(p1, v1);\n\n            Matrix3d m = Matrix3d.RotationMatrix(new Vector3d(0, -1, 1), 10 * PI / 180);\n            v1 = m * v1;\n            Plane3d s2 = new Plane3d(p1, v1);\n\n            Assert.IsTrue(Abs(s1.AngleToDeg(s2) - 10) < GeometRi3D.Tolerance);\n        }\n\n        [TestMethod()]\n        public void PlaneAngleToPlaneTest2()\n        {\n            Point3d p1 = new Point3d(1, 0, 0);\n            Vector3d v1 = new Vector3d(0, 1, 1);\n            Plane3d s1 = new Plane3d(p1, v1);\n\n            Matrix3d m = Matrix3d.RotationMatrix(new Vector3d(0, -1, 1), 10 * PI / 180);\n            v1 = m * v1;\n            Plane3d s2 = new Plane3d(p1, -v1);\n\n            Assert.IsTrue(Abs(s1.AngleToDeg(s2) - 10) < GeometRi3D.Tolerance);\n        }\n    }\n}\n"
  },
  {
    "path": "GeometRi.Tests/Point3DTest.cs",
    "content": "﻿using System;\nusing static System.Math;\nusing Microsoft.VisualStudio.TestTools.UnitTesting;\nusing GeometRi;\n\nnamespace GeometRi_Tests\n{\n    [TestClass]\n    public class Point3dTest\n    {\n        //===============================================================\n        // Point3d tests\n        //===============================================================\n\n        [TestMethod()]\n        public void PointAddDivideTest()\n        {\n            Point3d p1 = new Point3d(1, 2, 3);\n            Point3d p2 = new Point3d(3, 2, 1);\n            Assert.IsTrue((p1 + p2) / 2 == new Point3d(2, 2, 2));\n        }\n\n        [TestMethod()]\n        public void PointScaleTest()\n        {\n            Point3d p1 = new Point3d(1, 2, 3);\n            Point3d p2 = new Point3d(2, 4, 6);\n            Assert.IsTrue(2 * p1 == p2);\n        }\n\n        [TestMethod()]\n        public void PointDistanceToPointTest()\n        {\n            Point3d p1 = new Point3d(0, 0, 0);\n            Point3d p2 = new Point3d(0, 3, 4);\n            Assert.IsTrue(Abs(p1.DistanceTo(p2) - 5) < GeometRi3D.Tolerance);\n        }\n\n        [TestMethod()]\n        public void PointDistanceToLineTest()\n        {\n            Point3d p1 = new Point3d(-4, 3, 5);\n            Point3d p2 = new Point3d(1, -5, -1);\n            Vector3d v2 = new Vector3d(-2, 3, 4);\n            Line3d l1 = new Line3d(p2, v2);\n            Assert.IsTrue(Abs(p1.DistanceTo(l1) - 3) < GeometRi3D.Tolerance);\n\n            Assert.IsTrue(Abs(p1.DistanceSquared(l1) - 3*3) < GeometRi3D.Tolerance);\n        }\n\n        [TestMethod()]\n        public void PointDistanceToPlaneTest()\n        {\n            Point3d p1 = new Point3d(-4, 3, 5);\n            Plane3d s1 = new Plane3d(-1, 2, -2, 9);\n            Assert.IsTrue(Abs(p1.DistanceTo(s1) - 3) < GeometRi3D.Tolerance);\n            Assert.IsTrue(Abs(p1.DistanceSquared(s1) - 3*3) < GeometRi3D.Tolerance);\n        }\n\n        [TestMethod()]\n        public void PointDistanceToRayTest()\n        {\n            Point3d p = new Point3d(0, 0, 0);\n            Ray3d r = new Ray3d(new Point3d(1, 1, 0), new Vector3d(1, 0, 0));\n            Assert.IsTrue(Abs(p.DistanceTo(r) - Sqrt(2)) < GeometRi3D.Tolerance);\n\n            Assert.IsTrue(Abs(p.DistanceSquared  (r) - 2) < GeometRi3D.Tolerance);\n\n\n            p = new Point3d(2, 0, 0);\n            Assert.IsTrue(Abs(p.DistanceTo(r) - 1) < GeometRi3D.Tolerance);\n\n            Assert.IsTrue(Abs(p.DistanceSquared(r) - 1) < GeometRi3D.Tolerance);\n        }\n\n        [TestMethod()]\n        public void PointDistanceToSegmentTest()\n        {\n            Point3d p = new Point3d(0, 0, 0);\n            Segment3d s = new Segment3d(new Point3d(1, 1, 0), new Point3d(3, 3, 0));\n            Assert.IsTrue(Abs(p.DistanceTo(s) - Sqrt(2)) < GeometRi3D.Tolerance);\n            Assert.IsTrue(Abs(p.DistanceSquared(s) - 2) < GeometRi3D.Tolerance);\n\n            p = new Point3d(1, 1, 0);\n            Assert.IsTrue(Abs(p.DistanceTo(s) - 0) < GeometRi3D.Tolerance);\n            Assert.IsTrue(Abs(p.DistanceSquared(s) - 0) < GeometRi3D.Tolerance);\n\n            p = new Point3d(4, 4, 0);\n            Assert.IsTrue(Abs(p.DistanceTo(s) - Sqrt(2)) < GeometRi3D.Tolerance);\n            Assert.IsTrue(Abs(p.DistanceSquared(s) - 2) < GeometRi3D.Tolerance);\n\n            p = new Point3d(1, 3, 0);\n            Assert.IsTrue(Abs(p.DistanceTo(s) - Sqrt(2)) < GeometRi3D.Tolerance);\n            Assert.IsTrue(Abs(p.DistanceSquared(s) - 2) < GeometRi3D.Tolerance);\n        }\n\n        [TestMethod()]\n        public void PointProjectionToPlaneTest()\n        {\n            Point3d p1 = new Point3d(-4, 3, 5);\n            Plane3d s1 = new Plane3d(-1, 2, -2, 9);\n            Assert.IsTrue(p1.ProjectionTo(s1) == new Point3d(-3, 1, 7));\n\n            Coord3d coord1 = new Coord3d(new Point3d(2, 3, 1), Matrix3d.RotationMatrix(new Vector3d(2, 1, 5), PI / 3));\n            p1 = p1.ConvertTo(coord1);\n            Assert.IsTrue(p1.ProjectionTo(s1) == new Point3d(-3, 1, 7));\n        }\n\n        [TestMethod()]\n        public void PointProjectionToLineTest()\n        {\n            Point3d p1 = new Point3d(-4, 3, 5);\n            Point3d p2 = new Point3d(1, -5, -1);\n            Vector3d v2 = new Vector3d(-2, 3, 4);\n            Line3d l1 = new Line3d(p2, v2);\n            Assert.IsTrue(p1.ProjectionTo(l1) == new Point3d(-3, 1, 7));\n\n            Coord3d coord1 = new Coord3d(new Point3d(2, 3, 1), Matrix3d.RotationMatrix(new Vector3d(2, 1, 5), PI / 3));\n            p1 = p1.ConvertTo(coord1);\n            Assert.IsTrue(p1.ProjectionTo(l1) == new Point3d(-3, 1, 7));\n        }\n\n        [TestMethod()]\n        public void PointProjectionToSphereTest()\n        {\n            Point3d p1 = new Point3d(1, 1, 1);\n            Sphere s = new Sphere(p1, 2);\n            Point3d p2 = new Point3d(5, 5, 5);\n\n            Assert.IsTrue(p2.ProjectionTo(s) == new Point3d(1 + 2 / Sqrt(3), 1 + 2 / Sqrt(3), 1 + 2 / Sqrt(3)));\n\n            Coord3d coord1 = new Coord3d(new Point3d(2, 3, 1), Matrix3d.RotationMatrix(new Vector3d(2, 1, 5), PI / 3));\n            p2 = p2.ConvertTo(coord1);\n            Assert.IsTrue(p2.ProjectionTo(s) == new Point3d(1 + 2 / Sqrt(3), 1 + 2 / Sqrt(3), 1 + 2 / Sqrt(3)));\n        }\n\n        [TestMethod()]\n        public void PointBelongsToLineTest()\n        {\n            Point3d p1 = new Point3d(1, -5, -1);\n            Vector3d v1 = new Vector3d(-2, 3, 4);\n            Line3d l1 = new Line3d(p1, v1);\n            Point3d p2 = p1.Translate(3 * v1);\n            Assert.IsTrue(p2.BelongsTo(l1));\n        }\n\n        [TestMethod()]\n        public void PointBelongsToPlaneTest()\n        {\n            Plane3d s1 = new Plane3d(-1, 2, -2, 9);\n            Point3d p1 = s1.Point;\n            Assert.IsTrue(p1.BelongsTo(s1));\n\n            s1 = new Plane3d(new Point3d(0,0,10), new Vector3d(0,0,1));\n            p1 = new Point3d(0, 0, 10);\n            Assert.IsTrue(p1.BelongsTo(s1));\n\n            double tol = GeometRi3D.Tolerance;\n            bool mode = GeometRi3D.UseAbsoluteTolerance;\n            GeometRi3D.Tolerance = 0.01;\n            GeometRi3D.UseAbsoluteTolerance = false;\n\n            s1 = new Plane3d(new Point3d(0, 0, 10), new Vector3d(0, 0, 100));\n            p1 = new Point3d(0, 0, 10.05);\n            Assert.IsTrue(p1.BelongsTo(s1));\n            p1 = new Point3d(0, 0, 10.15);\n            Assert.IsFalse(p1.BelongsTo(s1));\n\n            // Resore initial state\n            GeometRi3D.UseAbsoluteTolerance = mode;\n            GeometRi3D.Tolerance = tol;\n        }\n\n        [TestMethod()]\n        public void PointBelongsToRayTest()\n        {\n            Point3d p = new Point3d(0, 0, 0);\n            Ray3d r = new Ray3d(new Point3d(1, 1, 0), new Vector3d(1, 0, 0));\n            Assert.IsFalse(p.BelongsTo(r));\n\n            p = new Point3d(1, 1, 0);\n            Assert.IsTrue(p.BelongsTo(r));\n\n            p = new Point3d(3, 1, 0);\n            Assert.IsTrue(p.BelongsTo(r));\n        }\n\n        [TestMethod()]\n        public void PointBelongsToSegmentTest()\n        {\n            Point3d p = new Point3d(0, 0, 0);\n            Segment3d s = new Segment3d(new Point3d(1, 1, 0), new Point3d(3, 3, 0));\n            Assert.IsFalse(p.BelongsTo(s));\n\n            p = new Point3d(1, 1, 0);\n            Assert.IsTrue(p.BelongsTo(s));\n            p = new Point3d(2, 2, 0);\n            Assert.IsTrue(p.BelongsTo(s));\n            p = new Point3d(3, 3, 0);\n            Assert.IsTrue(p.BelongsTo(s));\n        }\n\n        [TestMethod()]\n        public void PointEqualsNullTest()\n        {\n            Point3d p1 = null;\n            Point3d p2 = new Point3d(0, 0, 0);\n\n            Assert.IsTrue(p1 != p2);\n            Assert.IsFalse(p1 == p2);\n\n            p2 = null;\n            Assert.IsTrue(p1 == p2);\n            Assert.IsFalse(p1 != p2);\n        }\n    }\n}\n"
  },
  {
    "path": "GeometRi.Tests/Properties/AssemblyInfo.cs",
    "content": "using System.Reflection;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\n\n[assembly: AssemblyTitle(\"GeometRi.Tests\")]\n[assembly: AssemblyDescription(\"\")]\n[assembly: AssemblyConfiguration(\"\")]\n[assembly: AssemblyCompany(\"\")]\n[assembly: AssemblyProduct(\"GeometRi.Tests\")]\n[assembly: AssemblyCopyright(\"Copyright ©  2017\")]\n[assembly: AssemblyTrademark(\"\")]\n[assembly: AssemblyCulture(\"\")]\n\n[assembly: ComVisible(false)]\n\n[assembly: Guid(\"b99f3733-d205-4eda-9b4c-f2f68a9dfd59\")]\n\n// [assembly: AssemblyVersion(\"1.0.*\")]\n[assembly: AssemblyVersion(\"1.0.0.0\")]\n[assembly: AssemblyFileVersion(\"1.0.0.0\")]\n"
  },
  {
    "path": "GeometRi.Tests/QuaternionTest.cs",
    "content": "﻿using System;\nusing static System.Math;\nusing Microsoft.VisualStudio.TestTools.UnitTesting;\nusing GeometRi;\n\nnamespace GeometRi_Tests\n{\n    [TestClass]\n    public class QuaternionTest\n    {\n        [TestMethod]\n        public void IdentityMatrixTest()\n        {\n            Matrix3d m = Matrix3d.Identity();\n            Quaternion q = new Quaternion(m);\n            Assert.AreEqual(q, new Quaternion(1, 0, 0, 0));\n        }\n\n        [TestMethod]\n        public void ZeroRotationTest()\n        {\n            Rotation r = new Rotation();\n            Assert.AreEqual(r.ToQuaternion, new Quaternion(1, 0, 0, 0));\n        }\n    }\n}\n"
  },
  {
    "path": "GeometRi.Tests/Ray3DTest.cs",
    "content": "﻿using System;\nusing static System.Math;\nusing Microsoft.VisualStudio.TestTools.UnitTesting;\nusing GeometRi;\n\nnamespace GeometRi_Tests\n{\n    [TestClass]\n    public class Ray3dTest\n    {\n        //===============================================================\n        // Ray3d tests\n        //===============================================================\n\n        [TestMethod()]\n        public void RayDistanceToCrossingLineTest()\n        {\n            Line3d l = new Line3d(new Point3d(0, 0, 0), new Vector3d(1, 0, 0));\n            Ray3d r = new Ray3d(new Point3d(2, -3, 3), new Vector3d(0, 1, 0));\n            Assert.IsTrue(Abs(r.DistanceTo(l) - 3) < GeometRi3D.Tolerance);\n        }\n\n        [TestMethod()]\n        public void RayDistanceToCrossingLineTest2()\n        {\n            Line3d l = new Line3d(new Point3d(0, 0, 0), new Vector3d(1, 0, 0));\n            Ray3d r = new Ray3d(new Point3d(2, 4, 3), new Vector3d(0, 1, 0));\n            Assert.IsTrue(Abs(r.DistanceTo(l) - 5) < GeometRi3D.Tolerance);\n        }\n\n        [TestMethod()]\n        public void RayIntersectionWithPlaneTest()\n        {\n            Plane3d s = new Plane3d(0, 0, 1, 0);\n            Ray3d r = new Ray3d(new Point3d(-1, -1, -1), new Vector3d(1, 1, 1));\n            Assert.IsTrue((Point3d)r.IntersectionWith(s) == new Point3d(0, 0, 0));\n        }\n\n        [TestMethod()]\n        public void RayIntersectionWithPlaneTest2()\n        {\n            Plane3d s = new Plane3d(0, 0, 1, 0);\n            Ray3d r = new Ray3d(new Point3d(1, 1, 1), new Vector3d(1, 1, 1));\n            Assert.IsTrue(r.IntersectionWith(s) == null);\n        }\n\n        [TestMethod()]\n        public void RayIntersectionWithLineTest()\n        {\n            Line3d l = new Line3d(new Point3d(0, 0, 0), new Vector3d(1, 0, 0));\n            Ray3d r = new Ray3d(new Point3d(1, 0, 0), new Vector3d(1, 0, 0));\n            Assert.AreEqual(r.IntersectionWith(l), r);\n\n            r = new Ray3d(new Point3d(1, 0, 0), new Vector3d(1, 1, 1));\n            Assert.AreEqual(r.IntersectionWith(l), new Point3d(1, 0, 0));\n\n            r = new Ray3d(new Point3d(1, 1, 0), new Vector3d(1, -1, 0));\n            Assert.AreEqual(r.IntersectionWith(l), new Point3d(2, 0, 0));\n\n            r = new Ray3d(new Point3d(1, 1, 0), new Vector3d(1, -1, 1));\n            Assert.IsNull(r.IntersectionWith(l));\n        }\n\n        [TestMethod()]\n        public void RayIntersectionWithSegmentTest()\n        {\n            Segment3d s = new Segment3d(new Point3d(0, 0, 0), new Point3d(10, 0, 0));\n            Ray3d r = new Ray3d(new Point3d(-1, 0, 0), new Vector3d(1, 0, 0));\n            Assert.AreEqual(r.IntersectionWith(s), s);\n\n            r = new Ray3d(new Point3d(0, 0, 0), new Vector3d(1, 0, 0));\n            Assert.AreEqual(r.IntersectionWith(s), s);\n\n            r = new Ray3d(new Point3d(1, 0, 0), new Vector3d(1, 0, 0));\n            Assert.AreEqual(r.IntersectionWith(s), new Segment3d(new Point3d(1, 0, 0), new Point3d(10, 0, 0)));\n\n            r = new Ray3d(new Point3d(5, 0, 0), new Vector3d(-1, 0, 0));\n            Assert.AreEqual(r.IntersectionWith(s), new Segment3d(new Point3d(0, 0, 0), new Point3d(5, 0, 0)));\n\n            r = new Ray3d(new Point3d(10, 0, 0), new Vector3d(1, 0, 0));\n            Assert.AreEqual(r.IntersectionWith(s), new Point3d(10, 0, 0));\n\n            r = new Ray3d(new Point3d(0, 0, 0), new Vector3d(-1, 0, 0));\n            Assert.AreEqual(r.IntersectionWith(s), new Point3d(0, 0, 0));\n\n            r = new Ray3d(new Point3d(1, 1, 0), new Vector3d(1, -1, 0));\n            Assert.AreEqual(r.IntersectionWith(s), new Point3d(2, 0, 0));\n\n            r = new Ray3d(new Point3d(1, 1, 0), new Vector3d(1, -1, 1));\n            Assert.IsNull(r.IntersectionWith(s));\n        }\n\n        [TestMethod()]\n        public void RayIntersectionWithRayTest()\n        {\n            Ray3d r1 = new Ray3d(new Point3d(0, 0, 0), new Vector3d(1, 0, 0));\n            Ray3d r2 = new Ray3d(new Point3d(0, 0, 0), new Vector3d(1, 0, 0));\n            Assert.AreEqual(r1.IntersectionWith(r2), r1);\n\n            r2 = new Ray3d(new Point3d(-1, 0, 0), new Vector3d(1, 0, 0));\n            Assert.AreEqual(r1.IntersectionWith(r2), r1);\n\n            r2 = new Ray3d(new Point3d(1, 0, 0), new Vector3d(1, 0, 0));\n            Assert.AreEqual(r1.IntersectionWith(r2), r2);\n\n            r2 = new Ray3d(new Point3d(0, 0, 0), new Vector3d(-1, 0, 0));\n            Assert.AreEqual(r1.IntersectionWith(r2), new Point3d(0, 0, 0));\n\n            r2 = new Ray3d(new Point3d(1, 0, 0), new Vector3d(-1, 0, 0));\n            Assert.AreEqual(r1.IntersectionWith(r2), new Segment3d(new Point3d(0, 0, 0), new Point3d(1, 0, 0)));\n\n            r2 = new Ray3d(new Point3d(1, 1, 0), new Vector3d(1, -1, 0));\n            Assert.AreEqual(r1.IntersectionWith(r2), new Point3d(2, 0, 0));\n\n            r2 = new Ray3d(new Point3d(1, 1, 0), new Vector3d(1, -1, 1));\n            Assert.IsNull(r1.IntersectionWith(r2));\n        }\n\n        [TestMethod()]\n        public void RayProjectionToPlaneTest()\n        {\n            Plane3d s = new Plane3d(0, 0, 1, 0);\n            Ray3d r = new Ray3d(new Point3d(1, 1, 1), new Vector3d(1, 1, 1));\n            Assert.IsTrue((Ray3d)r.ProjectionTo(s) == new Ray3d(new Point3d(1, 1, 0), new Vector3d(1, 1, 0)));\n        }\n\n        [TestMethod()]\n        public void RayDistanceToRayTest()\n        {\n            Ray3d r1 = new Ray3d(new Point3d(0, 0, 0), new Vector3d(1, 0, 0));\n            Ray3d r2 = new Ray3d(new Point3d(5, 0, 5), new Vector3d(-1, 0, 0));\n            Assert.IsTrue(Abs(r1.DistanceTo(r2) - 5) < GeometRi3D.Tolerance);\n\n            r2 = new Ray3d(new Point3d(5, -5, 5), new Vector3d(0, 1, 0));\n            Assert.IsTrue(Abs(r1.DistanceTo(r2) - 5) < GeometRi3D.Tolerance);\n\n            r2 = new Ray3d(new Point3d(-5, 0, 5), new Vector3d(0, 1, 1));\n            Assert.IsTrue(Abs(r1.DistanceTo(r2) - Sqrt(50)) < GeometRi3D.Tolerance);\n        }\n\n        [TestMethod()]\n        public void RayDistanceToRayTest_02()\n        {\n            Ray3d r1 = new Ray3d(new Point3d(0, 0, 0), new Vector3d(1, 0, 0));\n            Ray3d r2 = new Ray3d(new Point3d(-1, 0, 0), new Vector3d(-1, 0, 0));\n            Assert.IsTrue(Abs(r1.DistanceTo(r2) - 1) < GeometRi3D.Tolerance);\n\n        }\n\n    }\n}\n"
  },
  {
    "path": "GeometRi.Tests/ReflectTest.cs",
    "content": "﻿using System;\nusing static System.Math;\nusing Microsoft.VisualStudio.TestTools.UnitTesting;\nusing GeometRi;\n\nnamespace GeometRi_Tests\n{\n    [TestClass]\n    public class ReflectTest\n    {\n        //===============================================================\n        // Object reflection tests\n        //===============================================================\n\n        [TestMethod()]\n        public void PointReflectInPointTest()\n        {\n            Point3d p1 = new Point3d(2, 3, 4);\n            Point3d p2 = new Point3d(1, 1, 1);\n\n            Assert.IsTrue(p1.ReflectIn(p2) == new Point3d(0, -1, -2));\n        }\n\n        [TestMethod()]\n        public void PointReflectInLineTest()\n        {\n            Point3d p1 = new Point3d(2, 3, 4);\n            Point3d p2 = new Point3d(1, 1, 1);\n            Line3d l = new Line3d(p2, new Vector3d(0, 0, 1));\n\n            Assert.IsTrue(p1.ReflectIn(l) == new Point3d(0, -1, 4));\n        }\n\n        [TestMethod()]\n        public void PointReflectInPlaneTest()\n        {\n            Point3d p1 = new Point3d(3, 3, 3);\n            Plane3d s = new Plane3d(1, 1, 1, -3);\n\n            Assert.IsTrue(p1.ReflectIn(s) == new Point3d(-1, -1, -1));\n        }\n\n        [TestMethod()]\n        public void LineReflectInPointTest()\n        {\n            Point3d p1 = new Point3d(1, 1, 1);\n            Line3d l1 = new Line3d(new Point3d(2, 3, 0), new Vector3d(0, 0, 1));\n            Line3d l2 = new Line3d(new Point3d(0, -1, 2), new Vector3d(0, 0, 1));\n\n            Assert.IsTrue(l1.ReflectIn(p1) == l2);\n        }\n\n        [TestMethod()]\n        public void PlaneReflectInPlaneTest()\n        {\n            Coord3d coord1 = new Coord3d(new Point3d(2, 3, 1), Matrix3d.RotationMatrix(new Vector3d(2, 1, 5), PI / 3));\n            Coord3d coord2 = new Coord3d(new Point3d(1, -3, 4), Matrix3d.RotationMatrix(new Vector3d(3, 2, 1), PI / 2));\n\n            Plane3d s1 = new Plane3d(1, 2, -2, -3, coord1);\n            Plane3d s2 = new Plane3d(2, -1, 3, -1, coord2);\n            Plane3d s3 = s1.ReflectIn(s2);\n            s3.Point = s3.Point.ConvertTo(coord2);\n            Plane3d s4 = s3.ReflectIn(s2);\n\n            bool bol = s4.Equals(s1);\n\n            Assert.IsTrue(s4 == s1);\n        }\n\n        [TestMethod()]\n        public void LineReflectInLineTest()\n        {\n            Coord3d coord1 = new Coord3d(new Point3d(2, 3, 1), Matrix3d.RotationMatrix(new Vector3d(2, 1, 5), PI / 3));\n            Coord3d coord2 = new Coord3d(new Point3d(1, -3, 4), Matrix3d.RotationMatrix(new Vector3d(3, 2, 1), PI / 2));\n\n            Line3d l1 = new Line3d(new Point3d(2, 3, 4, coord1), new Vector3d(2, 1, -3));\n            Line3d l2 = new Line3d(new Point3d(2, 3, 4, coord2), new Vector3d(2, 1, -3));\n            Line3d lt = l1.ReflectIn(l2);\n            lt.Point = lt.Point.ConvertTo(coord2);\n\n            Assert.IsTrue(lt.ReflectIn(l2) == l1);\n        }\n\n    }\n}\n"
  },
  {
    "path": "GeometRi.Tests/RelativeToleranceTest.cs",
    "content": "﻿using System;\nusing Microsoft.VisualStudio.TestTools.UnitTesting;\n\nnamespace GeometRi.Tests\n{\n    [TestClass]\n    public class RelativeToleranceTest\n    {\n        [TestMethod]\n        public void Segment3dRelativeToleranceTest()\n        {\n            Segment3d s1 = new Segment3d(new Point3d(0, 0, 0), new Point3d(100, 0, 0));\n            Segment3d s2 = new Segment3d(new Point3d(0, 0, 0), new Point3d(100, 0.99, 0));\n            Assert.AreNotEqual(s1, s2);\n\n            GeometRi3D.Tolerance = 0.01;\n            GeometRi3D.UseAbsoluteTolerance = false;\n            Assert.AreEqual(s1, s2);\n            GeometRi3D.Tolerance = 1e-12;\n            GeometRi3D.UseAbsoluteTolerance = true;\n        }\n\n        [TestMethod]\n        public void SphereRelativeToleranceTest()\n        {\n            Sphere s1 = new Sphere(new Point3d(100, 100, 0), 10);\n            Sphere s2 = new Sphere(new Point3d(100, 100.09, 0), 10);\n            Assert.AreNotEqual(s1, s2);\n\n            GeometRi3D.Tolerance = 0.01;\n            GeometRi3D.UseAbsoluteTolerance = false;\n            Assert.AreEqual(s1, s2);\n            GeometRi3D.Tolerance = 1e-12;\n            GeometRi3D.UseAbsoluteTolerance = true;\n        }\n\n        [TestMethod]\n        public void Circle3dRelativeToleranceTest()\n        {\n            Circle3d s1 = new Circle3d(new Point3d(100, 100, 0), 10, new Vector3d(1, 0, 0));\n            Circle3d s2 = new Circle3d(new Point3d(100, 100.09, 0), 10, new Vector3d(10, 0.09, 0));\n            Assert.AreNotEqual(s1, s2);\n\n            GeometRi3D.Tolerance = 0.01;\n            GeometRi3D.UseAbsoluteTolerance = false;\n            Assert.AreEqual(s1, s2);\n            GeometRi3D.Tolerance = 1e-12;\n            GeometRi3D.UseAbsoluteTolerance = true;\n        }\n\n        [TestMethod]\n        public void Point3dRelativeToleranceTest()\n        {\n            Point3d p1 = new Point3d(100, 100, 0);\n            Point3d p2 = new Point3d(100, 100, 0.9);\n            Assert.AreNotEqual(p1, p2);\n\n            GeometRi3D.Tolerance = 0.01;\n            GeometRi3D.UseAbsoluteTolerance = false;\n            Assert.AreEqual(p1, p2);\n            GeometRi3D.Tolerance = 1e-12;\n            GeometRi3D.UseAbsoluteTolerance = true;\n        }\n\n        [TestMethod]\n        public void Vector3dRelativeToleranceTest()\n        {\n            Vector3d v1 = new Vector3d(100, 100, 0);\n            Vector3d v2 = new Vector3d(100, 100, 0.9);\n            Assert.AreNotEqual(v1, v2);\n\n            GeometRi3D.Tolerance = 0.01;\n            GeometRi3D.UseAbsoluteTolerance = false;\n            Assert.AreEqual(v1, v2);\n            Assert.IsTrue(v1.IsParallelTo(v2));\n            GeometRi3D.Tolerance = 1e-12;\n            GeometRi3D.UseAbsoluteTolerance = true;\n        }\n\n        [TestMethod]\n        public void Vector3dIsParallelToRelativeToleranceTest()\n        {\n            Vector3d v1 = new Vector3d(-10, -10, -10);\n            Vector3d v2 = new Vector3d(199, 198, 198);\n            Assert.IsFalse(v1.IsParallelTo(v2));\n\n            GeometRi3D.Tolerance = 0.01;\n            GeometRi3D.UseAbsoluteTolerance = false;\n            Assert.IsTrue(v1.IsParallelTo(v2));\n            GeometRi3D.Tolerance = 1e-12;\n            GeometRi3D.UseAbsoluteTolerance = true;\n        }\n\n        [TestMethod]\n        public void Vector3dIsOrthogonalToRelativeToleranceTest()\n        {\n            Vector3d v1 = new Vector3d(-10, -10, 0);\n            Vector3d v2 = new Vector3d(1, 0, 198);\n            Assert.IsFalse(v1.IsOrthogonalTo(v2));\n\n            GeometRi3D.Tolerance = 0.01;\n            GeometRi3D.UseAbsoluteTolerance = false;\n            Assert.IsTrue(v1.IsOrthogonalTo(v2));\n            GeometRi3D.Tolerance = 1e-12;\n            GeometRi3D.UseAbsoluteTolerance = true;\n        }\n\n        [TestMethod]\n        public void Line3dRelativeToleranceTest()\n        {\n            Line3d l1 = new Line3d(new Point3d(2, 2, 2), new Vector3d(1, 1, 1));\n            Line3d l2 = new Line3d(new Point3d(201, 200, 200), new Vector3d(-10, -10, -10));\n            Assert.AreNotEqual(l1, l2);\n\n            GeometRi3D.Tolerance = 0.01;\n            GeometRi3D.UseAbsoluteTolerance = false;\n            Assert.AreEqual(l1, l2);\n            Assert.IsTrue(l1.IsParallelTo(l2));\n            GeometRi3D.Tolerance = 1e-12;\n            GeometRi3D.UseAbsoluteTolerance = true;\n        }\n    }\n}\n"
  },
  {
    "path": "GeometRi.Tests/RotateTest.cs",
    "content": "﻿using System;\nusing static System.Math;\nusing Microsoft.VisualStudio.TestTools.UnitTesting;\nusing GeometRi;\n\nnamespace GeometRi_Tests\n{\n    [TestClass]\n    public class RotateTest\n    {\n        //===============================================================\n        // Object rotation tests\n        //===============================================================\n\n        [TestMethod()]\n        public void PointRotationTest()\n        {\n            Matrix3d r = Matrix3d.RotationMatrix(new Vector3d(0, 0, 1), PI / 2);\n            Point3d p = new Point3d(1, 2, 0);\n\n            Assert.IsTrue(p.Rotate(r) == new Point3d(-2, 1, 0));\n\n            Rotation q = new Rotation(new Vector3d(0, 0, 1), PI / 2);\n            Assert.IsTrue(p.Rotate(q) == new Point3d(-2, 1, 0));\n\n        }\n\n        [TestMethod()]\n        public void PointRotationAroundPointTest()\n        {\n            Matrix3d r = Matrix3d.RotationMatrix(new Vector3d(0, 0, 1), PI / 2);\n            Point3d p = new Point3d(3, 3, 0);\n            Point3d pc = new Point3d(2, 3, 5);\n\n            Assert.IsTrue(p.Rotate(r, pc) == new Point3d(2, 4, 0));\n\n            Rotation q = new Rotation(new Vector3d(0, 0, 1), PI / 2);\n            Assert.IsTrue(p.Rotate(q, pc) == new Point3d(2, 4, 0));\n        }\n\n        [TestMethod()]\n        public void PointRotationAroundPointTest2()\n        {\n            Matrix3d r = Matrix3d.RotationMatrix(new Vector3d(1, 1, 1), 2 * PI / 3);\n            Point3d p = new Point3d(5, 0, 2);\n            Point3d pc = new Point3d(1, 1, 3);\n\n            Assert.IsTrue(p.Rotate(r, pc) == new Point3d(0, 5, 2));\n\n            Rotation q = new Rotation(new Vector3d(1, 1, 1), 2 * PI / 3);\n            Assert.IsTrue(p.Rotate(q, pc) == new Point3d(0, 5, 2));\n        }\n\n        [TestMethod()]\n        public void VectorRotationTest()\n        {\n            Matrix3d r = Matrix3d.RotationMatrix(new Vector3d(1, 1, 1), 2 * PI / 3);\n            Vector3d v1 = new Vector3d(1, 1, 1);\n            Vector3d v2 = new Vector3d(1, 0, 0);\n\n            Assert.IsTrue(v1.Rotate(r) == v1 && v2.Rotate(r) == new Vector3d(0, 1, 0));\n\n            Rotation q = new Rotation(new Vector3d(1, 1, 1), 2 * PI / 3);\n            Assert.IsTrue(v1.Rotate(q) == v1 && v2.Rotate(q) == new Vector3d(0, 1, 0));\n        }\n\n        [TestMethod()]\n        public void LineRotationTest()\n        {\n            Matrix3d r = Matrix3d.RotationMatrix(new Vector3d(1, 1, 1), 2 * PI / 3);\n            Coord3d coord = new Coord3d(new Point3d(3, 2, 1), r);\n            Point3d p = new Point3d(5, 0, 2, coord);\n            Line3d l = new Line3d(new Point3d(4, 1, 2), new Vector3d(1, 2, 6));\n\n            Assert.IsTrue(l.Rotate(r, p).Rotate(r, p).Rotate(r, p) == l);\n\n            Rotation q = new Rotation(new Vector3d(1, 1, 1), 2 * PI / 3);\n            Assert.IsTrue(l.Rotate(q, p).Rotate(q, p).Rotate(q, p) == l);\n        }\n\n        [TestMethod()]\n        public void PlaneRotationTest()\n        {\n            Matrix3d r = Matrix3d.RotationMatrix(new Vector3d(1, 1, 1), 2 * PI / 3);\n            Coord3d coord = new Coord3d(new Point3d(3, 2, 1), r);\n            Point3d p = new Point3d(5, 0, 2, coord);\n            Plane3d s = new Plane3d(1, 2, 3, 4);\n\n            Assert.IsTrue(s.Rotate(r, p).Rotate(r, p).Rotate(r, p) == s);\n\n            Rotation q = new Rotation(new Vector3d(1, 1, 1), 2 * PI / 3);\n            Assert.IsTrue(s.Rotate(q, p).Rotate(q, p).Rotate(q, p) == s);\n        }\n    }\n}\n"
  },
  {
    "path": "GeometRi.Tests/RotationTest.cs",
    "content": "﻿using System;\nusing static System.Math;\nusing Microsoft.VisualStudio.TestTools.UnitTesting;\nusing GeometRi;\n\nnamespace GeometRi.Tests\n{\n    [TestClass]\n    public class RotationTest\n    {\n        [TestMethod]\n        public void RotationMatrixTest()\n        {\n            Vector3d v = new Vector3d(4, 111, 6);\n            double angle = 0.0515;\n\n            Rotation r = new Rotation(v, angle);\n\n            Assert.AreEqual(Matrix3d.RotationMatrix(v, angle), r.ToRotationMatrix);\n        }\n\n        [TestMethod]\n        public void InverseRotationTest()\n        {\n            // Inverse axis and negative angle should produce the same rotation\n            Vector3d v = new Vector3d(4, 111, 6);\n            double angle = 0.0515;\n\n            Rotation r1 = new Rotation(v, angle);\n            Rotation r2 = new Rotation(-v, -angle);\n            Assert.AreEqual(r1, r2);\n\n            Quaternion q1 = new Quaternion(v, angle);\n            Quaternion q2 = new Quaternion(-v, -angle);\n            Assert.AreEqual(q1, q2);\n        }\n\n        [TestMethod]\n        public void PI_RotationTest()\n        {\n            // +PI and -PI should produce the same rotation\n            Vector3d v = new Vector3d(4, 111, 6);\n\n            Rotation r1 = new Rotation(v, PI);\n            Rotation r2 = new Rotation(v, -PI);\n            Assert.AreEqual(r1, r2);\n\n            Quaternion q1 = new Quaternion(v, PI);\n            Quaternion q2 = new Quaternion(v, -PI);\n            // For such rotation quaternion representation is not unique!!!\n            Assert.IsTrue(q1 == q2 || q1 == q2.Conjugate);\n        }\n\n        [TestMethod]\n        public void AxisToFromQuaternionTest()\n        {\n            Vector3d v = new Vector3d(4, 111, 6);\n            double angle = 0.0515;\n\n            Quaternion q = new Quaternion(v, angle);\n\n            Assert.IsTrue(q.ToAxis.IsParallelTo(v));\n            Assert.IsTrue(GeometRi3D.AlmostEqual(q.ToAngle, angle));\n        }\n\n        [TestMethod]\n        public void RotationFromCoordTest()\n        {\n            Coord3d coord = new Coord3d(new Point3d(2, 3, 1), new Vector3d(2, 1, 5), new Vector3d(1, 1, 1));\n            Rotation r = new Rotation(coord);\n\n            Assert.AreEqual(r * Coord3d.GlobalCS.Xaxis, coord.Xaxis);\n            Assert.AreEqual(r * Coord3d.GlobalCS.Yaxis, coord.Yaxis);\n            Assert.AreEqual(r * Coord3d.GlobalCS.Zaxis, coord.Zaxis);\n        }\n\n        [TestMethod]\n        public void AxisToFromMatrixTest()\n        {\n            Vector3d v = new Vector3d(4, 111, 6);\n            double angle = 0.0515;\n\n            Rotation r = new Rotation(v, angle);\n\n            Assert.IsTrue(r.ToAxis.IsParallelTo(v));\n            Assert.IsTrue(GeometRi3D.AlmostEqual(r.ToAngle, angle));\n        }\n\n        [TestMethod]\n        public void QuaternionToFromMatrixTest()\n        {\n            Quaternion q = new Quaternion(0.5, 0.5, 100.5, 0.5);\n            Rotation r = new Rotation(q);\n            Assert.AreEqual(r.ToQuaternion, q);\n\n            q = new Quaternion(1.0 / Sqrt(3), 1.0 / Sqrt(3), 1.0 / Sqrt(3), 0.0);\n            r = new Rotation(q);\n            Assert.AreEqual(r.ToQuaternion, q);\n\n            q = new Quaternion(0.5, 0.5, 0.5, 0.5);\n            r = new Rotation(q);\n            Assert.AreEqual(r.ToQuaternion, q);\n\n            q = new Quaternion(0.0, 1.0 / Sqrt(3), 1.0 / Sqrt(3), 1.0 / Sqrt(3));\n            r = new Rotation(q);\n            Assert.AreEqual(r.ToQuaternion, q);\n\n            q = new Quaternion(1.0, 0.0, 0.0, 0.0);\n            r = new Rotation(q);\n            Assert.AreEqual(r.ToQuaternion, q);\n        }\n\n        [TestMethod]\n        public void FromEulerAnglesTest()\n        {\n            Rotation r = Rotation.FromEulerAngles(PI / 2, PI / 2, PI / 2, \"zxy\");\n            Rotation res = new Rotation(new Vector3d(1, 0, 0), PI / 2);\n            Assert.AreEqual(r, res);\n\n            r = Rotation.FromEulerAngles(PI / 2, -PI / 2, -PI / 2, \"ZYZ\");\n            res = new Rotation(new Vector3d(1, 0, 0), PI / 2);\n            Assert.AreEqual(r, res);\n\n            r = Rotation.FromEulerAngles(PI / 4, -PI / 2, PI / 4, \"zyx\");\n            res = new Rotation(new Vector3d(0, 1, 0), -PI / 2);\n            Assert.AreEqual(r, res);\n\n            r = Rotation.FromEulerAngles(PI / 4, -PI / 2, -PI / 4, \"ZYX\");\n            res = new Rotation(new Vector3d(0, 1, 0), -PI / 2);\n            Assert.AreEqual(r, res);\n        }\n\n        [TestMethod]\n        public void SLERPTest()\n        {\n            // Zero rotation test\n            Quaternion q0 = new Quaternion(1, 0, 0, 0);\n            Quaternion q1 = q0;\n            Quaternion q2 = q0;\n            Assert.AreEqual(Quaternion.SLERP(q1, q2, 0.5), q0);\n\n            // Interpolate from zero to 90 degrees\n            q1 = new Quaternion(new Vector3d(1, 2, 3), PI / 2);\n            q2 = new Quaternion(new Vector3d(1, 2, 3), PI / 4);\n            Assert.AreEqual(Quaternion.SLERP(q0, q1, 0.5), q2);\n\n            // Interpolate from zero to 180 degrees\n            q1 = new Quaternion(new Vector3d(1, -2, -3), PI);\n            q2 = new Quaternion(new Vector3d(1, -2, -3), PI / 2);\n            Assert.AreEqual(Quaternion.SLERP(q0, q1, 0.5), q2);\n\n            q1 = new Quaternion(new Vector3d(1, 2, -3), 0.9832);\n            q2 = new Quaternion(new Vector3d(10, -2, 0.5), 1.8945);\n            Quaternion q_0_5 = Quaternion.SLERP(q1, q2, 0.5);\n            Quaternion q_0_25 = Quaternion.SLERP(q1, q2, 0.25);\n            Quaternion q_0_75 = Quaternion.SLERP(q1, q2, 0.75);\n            Assert.AreEqual(Quaternion.SLERP(q1, q_0_5, 0.5), q_0_25);\n            Assert.AreEqual(Quaternion.SLERP(q_0_5, q2, 0.5), q_0_75);\n\n        }\n\n        [TestMethod]\n        public void ToEulerAnglesXYZTest()\n        {\n            double a1, a2, a3;\n            a1 = 0.43553;\n            a2 = 0.1233;\n            a3 = 1.2342354;\n            Rotation r = Rotation.FromEulerAngles(a1, a1, a3, \"XYZ\");\n            var res = r.ToEulerAngles(\"XYZ\");\n            Rotation r2 = Rotation.FromEulerAngles(res[0], res[1], res[2], \"XYZ\");\n            Assert.AreEqual(r, r2);\n\n            r = Rotation.FromEulerAngles(a1, a2, a3, \"zyx\");\n            res = r.ToEulerAngles(\"zyx\");\n            r2 = Rotation.FromEulerAngles(res[0], res[1], res[2], \"zyx\");\n            Assert.AreEqual(r, r2);\n\n            r = Rotation.FromEulerAngles(a1, a2, a3, \"XZY\");\n            res = r.ToEulerAngles(\"XZY\");\n            r2 = Rotation.FromEulerAngles(res[0], res[1], res[2], \"XZY\");\n            Assert.AreEqual(r, r2);\n\n            r = Rotation.FromEulerAngles(a1, a2, a3, \"yzx\");\n            res = r.ToEulerAngles(\"yzx\");\n            r2 = Rotation.FromEulerAngles(res[0], res[1], res[2], \"yzx\");\n            Assert.AreEqual(r, r2);\n\n            r = Rotation.FromEulerAngles(a1, a2, a3, \"YXZ\");\n            res = r.ToEulerAngles(\"YXZ\");\n            r2 = Rotation.FromEulerAngles(res[0], res[1], res[2], \"YXZ\");\n            Assert.AreEqual(r, r2);\n\n            r = Rotation.FromEulerAngles(a1, a2, a3, \"zxy\");\n            res = r.ToEulerAngles(\"zxy\");\n            r2 = Rotation.FromEulerAngles(res[0], res[1], res[2], \"zxy\");\n            Assert.AreEqual(r, r2);\n\n            r = Rotation.FromEulerAngles(a1, a2, a3, \"YZX\");\n            res = r.ToEulerAngles(\"YZX\");\n            r2 = Rotation.FromEulerAngles(res[0], res[1], res[2], \"YZX\");\n            Assert.AreEqual(r, r2);\n\n            r = Rotation.FromEulerAngles(a1, a2, a3, \"xzy\");\n            res = r.ToEulerAngles(\"xzy\");\n            r2 = Rotation.FromEulerAngles(res[0], res[1], res[2], \"xzy\");\n            Assert.AreEqual(r, r2);\n\n            r = Rotation.FromEulerAngles(a1, a2, a3, \"ZXY\");\n            res = r.ToEulerAngles(\"ZXY\");\n            r2 = Rotation.FromEulerAngles(res[0], res[1], res[2], \"ZXY\");\n            Assert.AreEqual(r, r2);\n\n            r = Rotation.FromEulerAngles(a1, a2, a3, \"yxz\");\n            res = r.ToEulerAngles(\"yxz\");\n            r2 = Rotation.FromEulerAngles(res[0], res[1], res[2], \"yxz\");\n            Assert.AreEqual(r, r2);\n\n            r = Rotation.FromEulerAngles(a1, a2, a3, \"ZYX\");\n            res = r.ToEulerAngles(\"ZYX\");\n            r2 = Rotation.FromEulerAngles(res[0], res[1], res[2], \"ZYX\");\n            Assert.AreEqual(r, r2);\n\n            r = Rotation.FromEulerAngles(a1, a2, a3, \"xyz\");\n            res = r.ToEulerAngles(\"xyz\");\n            r2 = Rotation.FromEulerAngles(res[0], res[1], res[2], \"xyz\");\n            Assert.AreEqual(r, r2);\n\n        }\n\n        [TestMethod]\n        public void ToEulerAnglesXYXTest()\n        {\n            double a1, a2, a3;\n            a1 = 0.43553;\n            a2 = 0.1233;\n            a3 = 1.2342354;\n            Rotation r = Rotation.FromEulerAngles(a1, a1, a3, \"XYX\");\n            var res = r.ToEulerAngles(\"XYX\");\n            Rotation r2 = Rotation.FromEulerAngles(res[0], res[1], res[2], \"XYX\");\n            Assert.AreEqual(r, r2);\n\n            r = Rotation.FromEulerAngles(a1, a2, a3, \"xyx\");\n            res = r.ToEulerAngles(\"xyx\");\n            r2 = Rotation.FromEulerAngles(res[0], res[1], res[2], \"xyx\");\n            Assert.AreEqual(r, r2);\n\n            r = Rotation.FromEulerAngles(a1, a2, a3, \"XZX\");\n            res = r.ToEulerAngles(\"XZX\");\n            r2 = Rotation.FromEulerAngles(res[0], res[1], res[2], \"XZX\");\n            Assert.AreEqual(r, r2);\n\n            r = Rotation.FromEulerAngles(a1, a2, a3, \"xzx\");\n            res = r.ToEulerAngles(\"xzx\");\n            r2 = Rotation.FromEulerAngles(res[0], res[1], res[2], \"xzx\");\n            Assert.AreEqual(r, r2);\n\n            r = Rotation.FromEulerAngles(a1, a2, a3, \"YXY\");\n            res = r.ToEulerAngles(\"YXY\");\n            r2 = Rotation.FromEulerAngles(res[0], res[1], res[2], \"YXY\");\n            Assert.AreEqual(r, r2);\n\n            r = Rotation.FromEulerAngles(a1, a2, a3, \"yxy\");\n            res = r.ToEulerAngles(\"yxy\");\n            r2 = Rotation.FromEulerAngles(res[0], res[1], res[2], \"yxy\");\n            Assert.AreEqual(r, r2);\n\n            r = Rotation.FromEulerAngles(a1, a2, a3, \"YZY\");\n            res = r.ToEulerAngles(\"YZY\");\n            r2 = Rotation.FromEulerAngles(res[0], res[1], res[2], \"YZY\");\n            Assert.AreEqual(r, r2);\n\n            r = Rotation.FromEulerAngles(a1, a2, a3, \"yzy\");\n            res = r.ToEulerAngles(\"yzy\");\n            r2 = Rotation.FromEulerAngles(res[0], res[1], res[2], \"yzy\");\n            Assert.AreEqual(r, r2);\n\n            r = Rotation.FromEulerAngles(a1, a2, a3, \"ZXZ\");\n            res = r.ToEulerAngles(\"ZXZ\");\n            r2 = Rotation.FromEulerAngles(res[0], res[1], res[2], \"ZXZ\");\n            Assert.AreEqual(r, r2);\n\n            r = Rotation.FromEulerAngles(a1, a2, a3, \"zxz\");\n            res = r.ToEulerAngles(\"zxz\");\n            r2 = Rotation.FromEulerAngles(res[0], res[1], res[2], \"zxz\");\n            Assert.AreEqual(r, r2);\n\n            r = Rotation.FromEulerAngles(a1, a2, a3, \"ZYZ\");\n            res = r.ToEulerAngles(\"ZYZ\");\n            r2 = Rotation.FromEulerAngles(res[0], res[1], res[2], \"ZYZ\");\n            Assert.AreEqual(r, r2);\n\n            r = Rotation.FromEulerAngles(a1, a2, a3, \"zyz\");\n            res = r.ToEulerAngles(\"zyz\");\n            r2 = Rotation.FromEulerAngles(res[0], res[1], res[2], \"zyz\");\n            Assert.AreEqual(r, r2);\n        }\n\n        [TestMethod]\n        public void ToEulerAnglesDegenerateTest()\n        {\n            // Degenerate test cases\n\n            double a1, a2, a3;\n            a1 = 0.0;\n            a2 = 0.0;\n            a3 = 0.0;\n            Rotation r = Rotation.FromEulerAngles(a1, a1, a3, \"XYZ\");\n            var res = r.ToEulerAngles(\"XYZ\");\n            Rotation r2 = Rotation.FromEulerAngles(res[0], res[1], res[2], \"XYZ\");\n            Assert.AreEqual(r, r2);\n\n            r = Rotation.FromEulerAngles(a1, a2, a3, \"xyx\");\n            res = r.ToEulerAngles(\"xyx\");\n            r2 = Rotation.FromEulerAngles(res[0], res[1], res[2], \"xyx\");\n            Assert.AreEqual(r, r2);\n\n            a1 = PI;\n            a2 = PI;\n            a3 = PI;\n            r = Rotation.FromEulerAngles(a1, a1, a3, \"XYZ\");\n            res = r.ToEulerAngles(\"XYZ\");\n            r2 = Rotation.FromEulerAngles(res[0], res[1], res[2], \"XYZ\");\n            Assert.AreEqual(r, r2);\n\n            r = Rotation.FromEulerAngles(a1, a2, a3, \"xyx\");\n            res = r.ToEulerAngles(\"xyx\");\n            r2 = Rotation.FromEulerAngles(res[0], res[1], res[2], \"xyx\");\n            Assert.AreEqual(r, r2);\n\n            a1 = -PI;\n            a2 = -PI;\n            a3 = -PI;\n            r = Rotation.FromEulerAngles(a1, a1, a3, \"XYZ\");\n            res = r.ToEulerAngles(\"XYZ\");\n            r2 = Rotation.FromEulerAngles(res[0], res[1], res[2], \"XYZ\");\n            Assert.AreEqual(r, r2);\n\n            r = Rotation.FromEulerAngles(a1, a2, a3, \"xyx\");\n            res = r.ToEulerAngles(\"xyx\");\n            r2 = Rotation.FromEulerAngles(res[0], res[1], res[2], \"xyx\");\n            Assert.AreEqual(r, r2);\n\n            a1 = -PI;\n            a2 = -PI / 2;\n            a3 = PI / 2;\n            r = Rotation.FromEulerAngles(a1, a1, a3, \"XYZ\");\n            res = r.ToEulerAngles(\"XYZ\");\n            r2 = Rotation.FromEulerAngles(res[0], res[1], res[2], \"XYZ\");\n            Assert.AreEqual(r, r2);\n\n            r = Rotation.FromEulerAngles(a1, a2, a3, \"xyx\");\n            res = r.ToEulerAngles(\"xyx\");\n            r2 = Rotation.FromEulerAngles(res[0], res[1], res[2], \"xyx\");\n            Assert.AreEqual(r, r2);\n        }\n\n    }\n}\n"
  },
  {
    "path": "GeometRi.Tests/Segment3dTest.cs",
    "content": "﻿using System;\nusing static System.Math;\nusing Microsoft.VisualStudio.TestTools.UnitTesting;\nusing GeometRi;\n\nnamespace GeometRi_Tests\n{\n    [TestClass]\n    public class Segment3dTest\n    {\n        //===============================================================\n        // Segment3d tests\n        //===============================================================\n\n        [TestMethod()]\n        public void SegmentProjectionToLineTest()\n        {\n            Line3d l = new Line3d(new Point3d(1, 1, 1), new Vector3d(0, 0, 1));\n            Segment3d r = new Segment3d(new Point3d(-1, -3, -2), new Point3d(-5, 1, -3));\n            Assert.IsTrue((Segment3d)r.ProjectionTo(l) == new Segment3d(new Point3d(1, 1, -2), new Point3d(1, 1, -3)));\n        }\n\n        [TestMethod()]\n        public void SegmentProjectionToLineTest2()\n        {\n            Line3d l = new Line3d(new Point3d(1, 1, 1), new Vector3d(0, 0, 1));\n            Segment3d r = new Segment3d(new Point3d(-1, -3, -2), new Point3d(-5, 1, -2));\n            Assert.IsTrue((Point3d)r.ProjectionTo(l) == new Point3d(1, 1, -2));\n        }\n\n        [TestMethod()]\n        public void SegmentProjectionToPlaneTest()\n        {\n            Plane3d s = new Plane3d(0, 0, 1, -1);\n            Segment3d r = new Segment3d(new Point3d(-1, -3, -2), new Point3d(-5, 1, -3));\n            Assert.IsTrue((Segment3d)r.ProjectionTo(s) == new Segment3d(new Point3d(-1, -3, 1), new Point3d(-5, 1, 1)));\n        }\n\n        [TestMethod()]\n        public void SegmentIntersectionWithPlaneTest()\n        {\n            Plane3d s = new Plane3d(0, 0, 1, -1);\n            Segment3d r = new Segment3d(new Point3d(-1, -3, -2), new Point3d(-5, 1, -3));\n            Assert.IsTrue(r.IntersectionWith(s) == null);\n\n            r = new Segment3d(new Point3d(-1, -3, 1), new Point3d(-5, 1, 6));\n            Assert.IsTrue((Point3d)r.IntersectionWith(s) == new Point3d(-1, -3, 1));\n\n            r = new Segment3d(new Point3d(-1, -3, -5), new Point3d(-5, 1, 1));\n            Assert.IsTrue((Point3d)r.IntersectionWith(s) == new Point3d(-5, 1, 1));\n\n            r = new Segment3d(new Point3d(-1, -3, 1), new Point3d(-5, 1, 1));\n            Assert.IsTrue((Segment3d)r.IntersectionWith(s) == r);\n        }\n\n        [TestMethod()]\n        public void SegmentDistanceToPlaneTest()\n        {\n            Plane3d s = new Plane3d(0, 0, 1, -1);\n            Segment3d r = new Segment3d(new Point3d(-1, -3, -2), new Point3d(-5, 1, -3));\n            Assert.IsTrue(Abs(r.DistanceTo(s) - 3) < GeometRi3D.Tolerance);\n\n            r = new Segment3d(new Point3d(-1, -3, 1), new Point3d(-5, 1, 6));\n            Assert.IsTrue(Abs(r.DistanceTo(s)) < GeometRi3D.Tolerance);\n\n            r = new Segment3d(new Point3d(-1, -3, -5), new Point3d(-5, 1, 1));\n            Assert.IsTrue(Abs(r.DistanceTo(s)) < GeometRi3D.Tolerance);\n\n            r = new Segment3d(new Point3d(-1, -3, 1), new Point3d(-5, 1, 1));\n            Assert.IsTrue(Abs(r.DistanceTo(s)) < GeometRi3D.Tolerance);\n        }\n\n        [TestMethod()]\n        public void SegmentDistanceToLineTest()\n        {\n            Line3d l = new Line3d(new Point3d(), new Vector3d(1, 0, 0));\n            Segment3d r = new Segment3d(new Point3d(-2, -3, 1), new Point3d(-5, 6, 1));\n            Assert.IsTrue(Abs(r.DistanceTo(l) - 1) < GeometRi3D.Tolerance);\n\n            r = new Segment3d(new Point3d(-2, 0, 1), new Point3d(-5, 6, 5));\n            Assert.IsTrue(Abs(r.DistanceTo(l) - 1) < GeometRi3D.Tolerance);\n\n            r = new Segment3d(new Point3d(-5, -6, 0), new Point3d(-2, -2, 0));\n            Assert.IsTrue(Abs(r.DistanceTo(l) - 2) < GeometRi3D.Tolerance);\n\n            r = new Segment3d(new Point3d(-5, -6, 0), new Point3d(0, 0, 0));\n            Assert.IsTrue(Abs(r.DistanceTo(l)) < GeometRi3D.Tolerance);\n        }\n\n        [TestMethod()]\n        public void SegmentIntersectionWithLineTest()\n        {\n            Line3d l = new Line3d(new Point3d(), new Vector3d(1, 0, 0));\n            Segment3d s = new Segment3d(new Point3d(-2, -3, 1), new Point3d(-5, 6, 1));\n            Assert.IsTrue(s.IntersectionWith(l) == null);\n\n            s = new Segment3d(new Point3d(1, 1, 0), new Point3d(1, 5, 0));\n            Assert.IsTrue(s.IntersectionWith(l) == null);\n\n            s = new Segment3d(new Point3d(5, 0, 0), new Point3d(10, 0, 0));\n            Assert.IsTrue((Segment3d)s.IntersectionWith(l) == s);\n\n            s = new Segment3d(new Point3d(5, 0, 0), new Point3d(10, 10, 10));\n            Assert.IsTrue((Point3d)s.IntersectionWith(l) == new Point3d(5, 0, 0));\n\n            s = new Segment3d(new Point3d(5, -1, 0), new Point3d(7, 1, 0));\n            Assert.IsTrue((Point3d)s.IntersectionWith(l) == new Point3d(6, 0, 0));\n        }\n\n        [TestMethod()]\n        public void SegmentIntersectionWithSegmentTest()\n        {\n            Segment3d s1 = new Segment3d(new Point3d(0, 0, 0), new Point3d(5, 5, 0));\n\n            // Coincided segments\n            Segment3d s2 = new Segment3d(new Point3d(5, 5, 0), new Point3d(0, 0, 0));\n            Assert.IsTrue((Segment3d)s1.IntersectionWith(s2) == s1);\n\n            // Parallel segments\n            s2 = new Segment3d(new Point3d(5, 5, 1), new Point3d(0, 0, 1));\n            Assert.IsNull(s1.IntersectionWith(s2));\n\n            // Collinear nonintersecting segments\n            s2 = new Segment3d(new Point3d(6, 6, 0), new Point3d(7, 7, 0));\n            Assert.IsNull(s1.IntersectionWith(s2));\n\n            // Nonintersecting segments\n            s2 = new Segment3d(new Point3d(2, 1, 0), new Point3d(5, 0, 0));\n            Assert.IsNull(s1.IntersectionWith(s2));\n\n            // Touching segments\n            s2 = new Segment3d(new Point3d(2, 2, 0), new Point3d(5, 0, 0));\n            Assert.IsTrue((Point3d)s1.IntersectionWith(s2) == new Point3d(2, 2, 0));\n\n            // Intersecting at one end\n            s2 = new Segment3d(new Point3d(3, 4, 0), new Point3d(0, 0, 0));\n            Assert.IsTrue((Point3d)s1.IntersectionWith(s2) == new Point3d(0, 0, 0));\n\n            // Intersecting at the middle\n            s2 = new Segment3d(new Point3d(2, 4, 0), new Point3d(4, 2, 0));\n            Assert.IsTrue((Point3d)s1.IntersectionWith(s2) == new Point3d(3, 3, 0));\n\n            // Overlaping segments, s1 > s2\n            s2 = new Segment3d(new Point3d(2, 2, 0), new Point3d(3, 3, 0));\n            Assert.IsTrue((Segment3d)s1.IntersectionWith(s2) == new Segment3d(new Point3d(2, 2, 0), new Point3d(3, 3, 0)));\n\n            // Overlaping segments, s2 > s1\n            s2 = new Segment3d(new Point3d(-2, -2, 0), new Point3d(7, 7, 0));\n            Assert.IsTrue((Segment3d)s1.IntersectionWith(s2) == new Segment3d(new Point3d(0, 0, 0), new Point3d(5, 5, 0)));\n\n            // Partly overlaping segments\n            s2 = new Segment3d(new Point3d(3, 3, 0), new Point3d(-2, -2, 0));\n            Assert.IsTrue((Segment3d)s1.IntersectionWith(s2) == new Segment3d(new Point3d(0, 0, 0), new Point3d(3, 3, 0)));\n\n        }\n\n\n        [TestMethod()]\n        public void SegmentIntersectionWithSegmentRelativeTest()\n        {\n            Segment3d s1 = new Segment3d(new Point3d(0, 0, 0), new Point3d(5, 5, 0));\n\n            double tol = GeometRi3D.Tolerance;\n            bool mode = GeometRi3D.UseAbsoluteTolerance;\n            GeometRi3D.Tolerance = 0.01;\n            GeometRi3D.UseAbsoluteTolerance = false;\n\n            // Coincided segments\n            Segment3d s2 = new Segment3d(new Point3d(5, 5, 0.0), new Point3d(0, 0, 0.01));\n            Assert.IsTrue((Segment3d)s1.IntersectionWith(s2) == s1);\n\n            // Parallel segments\n            s2 = new Segment3d(new Point3d(5, 5, 1.01), new Point3d(0, 0, 1));\n            Assert.IsNull(s1.IntersectionWith(s2));\n\n            // Collinear nonintersecting segments\n            s2 = new Segment3d(new Point3d(6, 6, 0.01), new Point3d(7, 7, 0));\n            Assert.IsNull(s1.IntersectionWith(s2));\n\n            // Nonintersecting segments\n            s2 = new Segment3d(new Point3d(2, 1, 0.01), new Point3d(5, 0, 0));\n            Assert.IsNull(s1.IntersectionWith(s2));\n\n            // Touching segments\n            s2 = new Segment3d(new Point3d(2, 2, 0.01), new Point3d(5, 0, 0));\n            Assert.IsTrue((Point3d)s1.IntersectionWith(s2) == new Point3d(2, 2, 0));\n\n            // Intersecting at one end\n            s2 = new Segment3d(new Point3d(3, 4, 0), new Point3d(0, 0, 0.001));\n            Assert.IsTrue((Point3d)s1.IntersectionWith(s2) == new Point3d(0, 0, 0));\n\n            // Intersecting at the middle\n            s2 = new Segment3d(new Point3d(2, 4, 0.01), new Point3d(4, 2, 0));\n            Assert.IsTrue((Point3d)s1.IntersectionWith(s2) == new Point3d(3, 3, 0));\n\n            // Overlaping segments, s1 > s2\n            s2 = new Segment3d(new Point3d(2, 2, 0.01), new Point3d(3, 3, 0));\n            Assert.IsTrue((Segment3d)s1.IntersectionWith(s2) == new Segment3d(new Point3d(2, 2, 0), new Point3d(3, 3, 0)));\n\n            // Overlaping segments, s2 > s1\n            s2 = new Segment3d(new Point3d(-2, -2, 0.01), new Point3d(7, 7, 0));\n            Assert.IsTrue((Segment3d)s1.IntersectionWith(s2) == new Segment3d(new Point3d(0, 0, 0), new Point3d(5, 5, 0)));\n\n            // Partly overlaping segments\n            s2 = new Segment3d(new Point3d(3, 3, 0.01), new Point3d(-2, -2, 0));\n            Assert.IsTrue((Segment3d)s1.IntersectionWith(s2) == new Segment3d(new Point3d(0, 0, 0), new Point3d(3, 3, 0)));\n\n            // Resore initial state\n            GeometRi3D.UseAbsoluteTolerance = mode;\n            GeometRi3D.Tolerance = tol;\n        }\n\n        [TestMethod()]\n        public void SegmentIntersectionWithSegmentSymmetryTest()\n        {\n            // Test symmetry in segment-segment intersection\n            // s1.IntersectionWith(s2) == s2.IntersectionWith(s1)\n\n            Segment3d s1 = new Segment3d(new Point3d(0, 0, 0), new Point3d(5, 5, 0));\n\n            // Coincided segments\n            Segment3d s2 = new Segment3d(new Point3d(5, 5, 0), new Point3d(0, 0, 0));\n            object obj1 = s1.IntersectionWith(s2);\n            object obj2 = s2.IntersectionWith(s1);\n            Assert.IsTrue((obj1 == null && obj2 == null) || (obj1 != null && obj2 != null));\n\n            // Non-parallel segments\n            s2 = new Segment3d(new Point3d(5, 5.000000001, 0), new Point3d(-0.0000000001, 0, 0));\n            obj1 = s1.IntersectionWith(s2);\n            obj2 = s2.IntersectionWith(s1);\n            Assert.IsTrue((obj1 == null && obj2 == null) || (obj1 != null && obj2 != null));\n\n            // Nearly parallel segments\n            s2 = new Segment3d(new Point3d(3, 3.000000000001, 0), new Point3d(6, 6, 0));\n            obj1 = s1.IntersectionWith(s2);\n            obj2 = s2.IntersectionWith(s1);\n            Assert.IsTrue((obj1 == null && obj2 == null) || (obj1 != null && obj2 != null));\n\n        }\n\n        [TestMethod()]\n        public void SegmentBelongsToLineTest()\n        {\n            Line3d l = new Line3d(new Point3d(), new Vector3d(1, 0, 0));\n            Segment3d r = new Segment3d(new Point3d(5, 0, 0), new Point3d(10, 0, 0));\n            Assert.IsTrue(r.BelongsTo(l));\n\n            r = new Segment3d(new Point3d(5, 0, 0), new Point3d(5, 5, 5));\n            Assert.IsFalse(r.BelongsTo(l));\n\n            r = new Segment3d(new Point3d(-5, -6, 0), new Point3d(-2, -2, 0));\n            Assert.IsFalse(r.BelongsTo(l));\n        }\n\n        [TestMethod()]\n        public void SegmentDistanceToSegmentTest()\n        {\n            Segment3d s1 = new Segment3d(new Point3d(-5, 0, 0), new Point3d(5, 0, 0));\n            Segment3d s2 = new Segment3d(new Point3d(-2, -3, 1), new Point3d(5, 6, 1));\n            Assert.IsTrue(Abs(s1.DistanceTo(s2) - 1) < GeometRi3D.Tolerance);\n\n            s2 = new Segment3d(new Point3d(6, -3, 1), new Point3d(6, 6, 1));\n            Assert.IsTrue(Abs(s1.DistanceTo(s2) - Sqrt(2)) < GeometRi3D.Tolerance);\n\n            s2 = new Segment3d(new Point3d(2, 4, 0), new Point3d(6, 8, 0));\n            Assert.IsTrue(Abs(s1.DistanceTo(s2) - 4) < GeometRi3D.Tolerance);\n\n            s2 = new Segment3d(new Point3d(2, 4, 5), new Point3d(4, 0, 2));\n            Assert.IsTrue(Abs(s1.DistanceTo(s2) - 2) < GeometRi3D.Tolerance);\n\n            s2 = new Segment3d(new Point3d(-7, -6, 0), new Point3d(-5, -2, 0));\n            Assert.IsTrue(Abs(s1.DistanceTo(s2) - 2) < GeometRi3D.Tolerance);\n        }\n\n        [TestMethod()]\n        public void SegmentDistanceToSegmentClosestPointsTest01()\n        {\n            // Parallel segments\n            //    P1-----------P2\n            //    P1-----------P2\n            Segment3d s1 = new Segment3d(new Point3d(0, 0, 0), new Point3d(5, 0, 0));\n            Segment3d s2 = new Segment3d(new Point3d(0, 0, 1), new Point3d(5, 0, 1));\n            double dist = s1.DistanceTo(s2, out Point3d p1, out Point3d p2);\n            Assert.IsTrue(Abs(dist - 1) < GeometRi3D.Tolerance);\n            Assert.IsTrue(p1 == s1.P1);\n            Assert.IsTrue(p2 == s2.P1);\n        }\n\n        [TestMethod()]\n        public void SegmentDistanceToSegmentClosestPointsTest02()\n        {\n            // Parallel segments\n            //    P2-----------P1\n            //    P1-----------P2\n            Segment3d s1 = new Segment3d(new Point3d(0, 0, 0), new Point3d(5, 0, 0));\n            Segment3d s2 = new Segment3d(new Point3d(5, 0, 1), new Point3d(0, 0, 1));\n            double dist = s1.DistanceTo(s2, out Point3d p1, out Point3d p2);\n            Assert.IsTrue(Abs(dist - 1) < GeometRi3D.Tolerance);\n            Assert.IsTrue(p1 == s1.P1);\n            Assert.IsTrue(p2 == s2.P2);\n        }\n\n        [TestMethod()]\n        public void SegmentDistanceToSegmentClosestPointsTest03()\n        {\n            // Parallel segments\n            //    P1-----------P2\n            //          P1-----------P2\n            Segment3d s1 = new Segment3d(new Point3d(0, 0, 0), new Point3d(5, 0, 0));\n            Segment3d s2 = new Segment3d(new Point3d(-2, 0, 1), new Point3d(2, 0, 1));\n            double dist = s1.DistanceTo(s2, out Point3d p1, out Point3d p2);\n            Assert.IsTrue(Abs(dist - 1) < GeometRi3D.Tolerance);\n            Assert.IsTrue(p1 == s1.P1);\n            Assert.IsTrue(p2 == new Point3d(0, 0, 1));\n        }\n\n        [TestMethod()]\n        public void SegmentDistanceToSegmentClosestPointsTest04()\n        {\n            // Parallel segments\n            //    P2-----------P1\n            //          P1-----------P2\n            Segment3d s1 = new Segment3d(new Point3d(0, 0, 0), new Point3d(5, 0, 0));\n            Segment3d s2 = new Segment3d(new Point3d(2, 0, 1), new Point3d(-2, 0, 1));\n            double dist = s1.DistanceTo(s2, out Point3d p1, out Point3d p2);\n            Assert.IsTrue(Abs(dist - 1) < GeometRi3D.Tolerance);\n            Assert.IsTrue(p1 == s1.P1);\n            Assert.IsTrue(p2 == new Point3d(0, 0, 1));\n        }\n\n        [TestMethod()]\n        public void SegmentDistanceToSegmentClosestPointsTest05()\n        {\n            // Parallel segments\n            //    P1-----------P2\n            //                    P1-----------P2\n            Segment3d s1 = new Segment3d(new Point3d(0, 0, 0), new Point3d(5, 0, 0));\n            Segment3d s2 = new Segment3d(new Point3d(-5, 0, 1), new Point3d(-1, 0, 1));\n            double dist = s1.DistanceTo(s2, out Point3d p1, out Point3d p2);\n            Assert.IsTrue(Abs(dist - Sqrt(2)) < GeometRi3D.Tolerance);\n            Assert.IsTrue(p1 == s1.P1);\n            Assert.IsTrue(p2 == s2.P2);\n        }\n\n        [TestMethod()]\n        public void SegmentDistanceToSegmentClosestPointsTest06()\n        {\n            // Parallel segments\n            //    P2-----------P1\n            //                    P1-----------P2\n            Segment3d s1 = new Segment3d(new Point3d(0, 0, 0), new Point3d(5, 0, 0));\n            Segment3d s2 = new Segment3d(new Point3d(-1, 0, 1), new Point3d(-5, 0, 1));\n            double dist = s1.DistanceTo(s2, out Point3d p1, out Point3d p2);\n            Assert.IsTrue(Abs(dist - Sqrt(2)) < GeometRi3D.Tolerance);\n            Assert.IsTrue(p1 == s1.P1);\n            Assert.IsTrue(p2 == s2.P1);\n\n            dist = s2.DistanceTo(s1, out p1, out p2);\n            Assert.IsTrue(Abs(dist - Sqrt(2)) < GeometRi3D.Tolerance);\n            Assert.IsTrue(p1 == s2.P1);\n            Assert.IsTrue(p2 == s1.P1);\n        }\n\n        [TestMethod()]\n        public void SegmentDistanceToSegmentClosestPointsTest07()\n        {\n            //                             /P2\n            //                    P1------/-----P2\n            //                           /\n            //                          /P1 \n            Segment3d s1 = new Segment3d(new Point3d(0, 0, 0), new Point3d(5, 0, 0));\n            Segment3d s2 = new Segment3d(new Point3d(0, -1, 0), new Point3d(2, 1, 0));\n            double dist = s1.DistanceTo(s2, out Point3d p1, out Point3d p2);\n            Assert.IsTrue(Abs(dist) < GeometRi3D.Tolerance);\n            Assert.IsTrue(p1 == new Point3d(1, 0, 0));\n            Assert.IsTrue(p2 == new Point3d(1, 0, 0));\n\n            dist = s2.DistanceTo(s1, out p1, out p2);\n            Assert.IsTrue(Abs(dist) < GeometRi3D.Tolerance);\n            Assert.IsTrue(p1 == new Point3d(1, 0, 0));\n            Assert.IsTrue(p2 == new Point3d(1, 0, 0));\n        }\n\n        [TestMethod()]\n        public void SegmentDistanceToSegmentClosestPointsTest08()\n        {\n            //                                       |P2\n            //                    P1-----------P2    |\n            //                                       |P1                           \n            Segment3d s1 = new Segment3d(new Point3d(0, 0, 0), new Point3d(5, 0, 0));\n            Segment3d s2 = new Segment3d(new Point3d(6, -1, 0), new Point3d(6, 1, 0));\n            double dist = s1.DistanceTo(s2, out Point3d p1, out Point3d p2);\n            Assert.IsTrue(Abs(dist-1) < GeometRi3D.Tolerance);\n            Assert.IsTrue(p1 == s1.P2);\n            Assert.IsTrue(p2 == new Point3d(6, 0, 0));\n\n            dist = s2.DistanceTo(s1, out p1, out p2);\n            Assert.IsTrue(Abs(dist-1) < GeometRi3D.Tolerance);\n            Assert.IsTrue(p1 == new Point3d(6, 0, 0));\n            Assert.IsTrue(p2 == s1.P2);\n        }\n\n        [TestMethod()]\n        public void SegmentDistanceToSegmentClosestPointsTest09()\n        {\n            //                               /P2\n            //                              /\n            //                             /P1\n            //                    P1-----------P2  \n                           \n            Segment3d s1 = new Segment3d(new Point3d(0, 0, 0), new Point3d(5, 0, 0));\n            Segment3d s2 = new Segment3d(new Point3d(3, 1, 0), new Point3d(6, 4, 0));\n            double dist = s1.DistanceTo(s2, out Point3d p1, out Point3d p2);\n            Assert.IsTrue(Abs(dist - 1) < GeometRi3D.Tolerance);\n            Assert.IsTrue(p1 == new Point3d(3, 0, 0));\n            Assert.IsTrue(p2 == s2.P1);\n\n            dist = s2.DistanceTo(s1, out p1, out p2);\n            Assert.IsTrue(Abs(dist - 1) < GeometRi3D.Tolerance);\n            Assert.IsTrue(p1 == s2.P1);\n            Assert.IsTrue(p2 == new Point3d(3, 0, 0));\n        }\n\n        [TestMethod()]\n        public void SegmentDistanceToSegmentClosestPointsTest10()\n        {\n            //                             /P2\n            //                    P1------/-----P2\n            //                           /\n            //                          /P1 \n            Segment3d s1 = new Segment3d(new Point3d(0, 0, 0), new Point3d(5, 0, 0));\n            Segment3d s2 = new Segment3d(new Point3d(0, -1, 1), new Point3d(2, 1, 1));\n            double dist = s1.DistanceTo(s2, out Point3d p1, out Point3d p2);\n            Assert.IsTrue(Abs(dist-1) < GeometRi3D.Tolerance);\n            Assert.IsTrue(p1 == new Point3d(1, 0, 0));\n            Assert.IsTrue(p2 == new Point3d(1, 0, 1));\n\n            dist = s2.DistanceTo(s1, out p1, out p2);\n            Assert.IsTrue(Abs(dist-1) < GeometRi3D.Tolerance);\n            Assert.IsTrue(p1 == new Point3d(1, 0, 1));\n            Assert.IsTrue(p2 == new Point3d(1, 0, 0));\n        }\n\n        [TestMethod()]\n        public void SegmentDistanceToRayTest()\n        {\n            Segment3d s1 = new Segment3d(new Point3d(-5, 0, 0), new Point3d(5, 0, 0));\n            Ray3d r = s1.ToRay;\n\n            Segment3d s2 = new Segment3d(new Point3d(-2, -3, 1), new Point3d(5, 6, 1));\n            Assert.IsTrue(Abs(s2.DistanceTo(r) - 1) < GeometRi3D.Tolerance);\n\n            s2 = new Segment3d(new Point3d(6, -3, 1), new Point3d(6, 6, 1));\n            Assert.IsTrue(Abs(s2.DistanceTo(r) - 1) < GeometRi3D.Tolerance);\n\n            s2 = new Segment3d(new Point3d(2, 4, 0), new Point3d(6, 8, 0));\n            Assert.IsTrue(Abs(s2.DistanceTo(r) - 4) < GeometRi3D.Tolerance);\n\n            s2 = new Segment3d(new Point3d(2, 4, 5), new Point3d(4, 0, 2));\n            Assert.IsTrue(Abs(s2.DistanceTo(r) - 2) < GeometRi3D.Tolerance);\n\n            s2 = new Segment3d(new Point3d(-7, -6, 0), new Point3d(-5, -2, 0));\n            Assert.IsTrue(Abs(s2.DistanceTo(r) - 2) < GeometRi3D.Tolerance);\n        }\n\n        [TestMethod()]\n        public void SegmentAngleToPlaneTest()\n        {\n            Plane3d s = new Plane3d(0, 0, 1, -1);\n            Segment3d r1 = new Segment3d(new Point3d(0, 0, 3), new Point3d(1, 0, 4));\n            Segment3d r2 = new Segment3d(new Point3d(0, 0, -3), new Point3d(1, 0, -4));\n            Assert.IsTrue(Abs(r1.AngleToDeg(s) - 45) < GeometRi3D.Tolerance && Abs(r1.AngleTo(s) - r2.AngleTo(s)) < GeometRi3D.Tolerance);\n        }\n\n        [TestMethod()]\n        public void SegmentEqualsTest()\n        {\n            Point3d p1 = new Point3d(1, 4, 6);\n            Point3d p2 = new Point3d(8, -4, 0);\n            Segment3d r1 = new Segment3d(p1, p2);\n            Segment3d r2 = new Segment3d(p2, p1);\n            Assert.IsTrue(r1 == r2);\n        }\n\n        [TestMethod]\n        public void PointInSegmentTest()\n        {\n            Point3d p = new Point3d(0, 0, 0);\n            Segment3d s = new Segment3d(p, new Point3d(10,0,0));\n\n            p = new Point3d(5, 0, 0);  // Point inside\n            Assert.IsTrue(p.BelongsTo(s));\n            Assert.IsTrue(p.IsInside(s));\n            Assert.IsFalse(p.IsOutside(s));\n            Assert.IsFalse(p.IsOnBoundary(s));\n\n            p = new Point3d(10, 0, 0);  // Point on boundary\n            Assert.IsTrue(p.BelongsTo(s));\n            Assert.IsFalse(p.IsInside(s));\n            Assert.IsFalse(p.IsOutside(s));\n            Assert.IsTrue(p.IsOnBoundary(s));\n\n            p = new Point3d(1, 3, 0);  // Point outside\n            Assert.IsFalse(p.BelongsTo(s));\n            Assert.IsFalse(p.IsInside(s));\n            Assert.IsTrue(p.IsOutside(s));\n            Assert.IsFalse(p.IsOnBoundary(s));\n\n            p = new Point3d(11, 0, 0);  // Point outside\n            Assert.IsFalse(p.BelongsTo(s));\n            Assert.IsFalse(p.IsInside(s));\n            Assert.IsTrue(p.IsOutside(s));\n            Assert.IsFalse(p.IsOnBoundary(s));\n        }\n\n        [TestMethod]\n        public void PointInSegmentRelativeTest()\n        {\n            Point3d p = new Point3d(0, 0, 0);\n            Segment3d s = new Segment3d(p, new Point3d(10, 0, 0));\n\n            double tol = GeometRi3D.Tolerance;\n            bool mode = GeometRi3D.UseAbsoluteTolerance;\n            GeometRi3D.Tolerance = 0.01;\n            GeometRi3D.UseAbsoluteTolerance = false;\n\n            p = new Point3d(5, 0, 0.05);  // Point inside\n            Assert.IsTrue(p.BelongsTo(s));\n            Assert.IsTrue(p.IsInside(s));\n            Assert.IsFalse(p.IsOutside(s));\n            Assert.IsFalse(p.IsOnBoundary(s));\n\n            p = new Point3d(10.05, 0, 0);  // Point on boundary\n            Assert.IsTrue(p.BelongsTo(s));\n            Assert.IsFalse(p.IsInside(s));\n            Assert.IsFalse(p.IsOutside(s));\n            Assert.IsTrue(p.IsOnBoundary(s));\n\n            p = new Point3d(1, 0.2, 0);  // Point outside\n            Assert.IsFalse(p.BelongsTo(s));\n            Assert.IsFalse(p.IsInside(s));\n            Assert.IsTrue(p.IsOutside(s));\n            Assert.IsFalse(p.IsOnBoundary(s));\n\n            p = new Point3d(10.2, 0, 0);  // Point outside\n            Assert.IsFalse(p.BelongsTo(s));\n            Assert.IsFalse(p.IsInside(s));\n            Assert.IsTrue(p.IsOutside(s));\n            Assert.IsFalse(p.IsOnBoundary(s));\n\n            // Resore initial state\n            GeometRi3D.UseAbsoluteTolerance = mode;\n            GeometRi3D.Tolerance = tol;\n        }\n\n        [TestMethod()]\n        public void SegmentDistanceToCircleTest()\n        {\n            Point3d p1 = new Point3d(-0.5, -0.5, -0.5);\n            Point3d p2 = new Point3d(0.5, 0.5, -0.5);\n            Segment3d s = new Segment3d(p1, p2);\n\n            Circle3d c = new Circle3d(new Point3d(-1.3195, -1.0435, -0.70047), 0.35, new Vector3d(0.83694, -0.13208, -0.53112));\n\n            double dist = s.DistanceTo(c);\n            Assert.IsTrue(dist > 0);\n\n        }\n\n        [TestMethod()]\n        public void SegmentDistanceToCircleTest_02()\n        {\n            Point3d p1 = new Point3d(0.301356040516408, 0.400483483427746, 0.583650524970757);\n            Point3d p2 = new Point3d(0.433915317785216, 0.662580513110059, 0.657843630090789);\n            Segment3d s = new Segment3d(p1, p2);\n\n            Circle3d c = new Circle3d(new Point3d(0.518083776391494, 0.532968496579738, 0.671849229166195), 0.175764204722922, new Vector3d(-0.308050408901554, -0.161312662726171, 0.93759435280924));\n\n            double dist = s.DistanceTo(c);\n            Assert.IsTrue(dist < GeometRi3D.Tolerance);\n\n        }\n    }\n}\n"
  },
  {
    "path": "GeometRi.Tests/SphereTest.cs",
    "content": "﻿using System;\nusing static System.Math;\nusing Microsoft.VisualStudio.TestTools.UnitTesting;\nusing GeometRi;\n\nnamespace GeometRi_Tests\n{\n    [TestClass]\n    public class SphereTest\n    {\n        //===============================================================\n        // Sphere tests\n        //===============================================================\n\n        [TestMethod()]\n        public void SphereEqualTest()\n        {\n            Sphere s1 = new Sphere(new Point3d(0, 0, 0), 5);\n            Sphere s2 = new Sphere(new Point3d(0, 0, 0), 6);\n            Assert.IsTrue(s1 != s2);\n\n            s1 = new Sphere(new Point3d(0, 0, 0), 5);\n            s2 = new Sphere(new Point3d(1, 0, 0), 5);\n            Assert.IsTrue(s1 != s2);\n\n            s1 = new Sphere(new Point3d(0, 0, 0), 5);\n            s2 = new Sphere(new Point3d(0, 0, 0), 5);\n            Assert.IsTrue(s1 == s2);\n        }\n\n        [TestMethod()]\n        public void SphereIntersectionWithLineTest()\n        {\n            Line3d l = new Line3d(new Point3d(5, 0, -6), new Vector3d(1, 0, 0));\n            Sphere s = new Sphere(new Point3d(0, 0, 0), 5);\n\n            Assert.IsTrue(s.IntersectionWith(l) == null);\n\n            l.Point = new Point3d(5, 0, -5);\n            Assert.IsTrue((Point3d)s.IntersectionWith(l) == new Point3d(0, 0, -5));\n\n            l.Point = new Point3d(0, 0, 0);\n            l.Direction = new Vector3d(1, 0, 0);\n            Assert.IsTrue((Segment3d)s.IntersectionWith(l) == new Segment3d(new Point3d(-5, 0, 0), new Point3d(5, 0, 0)));\n\n            l.Direction = new Vector3d(1, 3, 4);\n            Assert.IsTrue(((Segment3d)s.IntersectionWith(l)).Length == 10);\n        }\n\n        [TestMethod()]\n        public void SphereIntersectionWithSegmentRelativeTest()\n        {\n\n            double tol = GeometRi3D.Tolerance;\n            bool mode = GeometRi3D.UseAbsoluteTolerance;\n            GeometRi3D.Tolerance = 0.01;\n            GeometRi3D.UseAbsoluteTolerance = false;\n\n            Sphere s = new Sphere(new Point3d(0, 0, 0), 5);\n            Segment3d l = new Segment3d(new Point3d(10, 12, 13), new Point3d(22, 23, 24));\n            Assert.IsTrue(s.IntersectionWith(l) == null);\n\n            l = new Segment3d(new Point3d(-2, -2, -1), new Point3d(1, 2, 2));\n            Assert.IsTrue((Segment3d)s.IntersectionWith(l) == l);\n\n            l = new Segment3d(new Point3d(5.01, 0, 0), new Point3d(25, 0, 0));\n            Assert.IsTrue((Point3d)s.IntersectionWith(l) == new Point3d(5, 0, 0));\n\n            l = new Segment3d(new Point3d(0, 0, 0), new Point3d(25, 0, 0));\n            Assert.IsTrue((Segment3d)s.IntersectionWith(l) == new Segment3d(new Point3d(0, 0, 0), new Point3d(5, 0, 0)));\n\n            // Resore initial state\n            GeometRi3D.UseAbsoluteTolerance = mode;\n            GeometRi3D.Tolerance = tol;\n        }\n\n        [TestMethod()]\n        public void SphereIntersectionWithRayTest()\n        {\n\n            Sphere s = new Sphere(new Point3d(0, 0, 0), 5);\n            Ray3d r = new Ray3d(new Point3d(0, 0, 0), new Vector3d(1, 0, 0));\n            Assert.AreEqual(r.IntersectionWith(s), new Segment3d(new Point3d(0, 0, 0), new Point3d(5, 0, 0)));\n\n            r = new Ray3d(new Point3d(0, 5, 0), new Vector3d(1, 0, 0));\n            Assert.AreEqual(s.IntersectionWith(r), new Point3d(0, 5, 0));\n        }\n\n        [TestMethod()]\n        public void SphereIntersectionWithPlaneTest()\n        {\n            Sphere s = new Sphere(new Point3d(1, -1, 3), 3);\n            Plane3d p = new Plane3d(1, 4, 5, 6);\n            Circle3d c = (Circle3d)s.IntersectionWith(p);\n            Assert.IsTrue(Abs(c.R - 1.13) < 0.005);\n            Assert.IsTrue(c.Center.DistanceTo(new Point3d(0.57, -2.71, 0.86)) < 0.01);\n        }\n\n        [TestMethod()]\n        public void SphereIntersectionWithSphereTest()\n        {\n            Sphere s1 = new Sphere(new Point3d(-2, 2, 4), 5);\n            Sphere s2 = new Sphere(new Point3d(3, 7, 3), 5);\n            Circle3d c1 = (Circle3d)s1.IntersectionWith(s2);\n            Assert.IsTrue(Abs(c1.R - 3.5) < GeometRi3D.Tolerance);\n            Assert.IsTrue(c1.Center == new Point3d(0.5, 4.5, 3.5));\n\n            Circle3d c2 = (Circle3d)s2.IntersectionWith(s1);\n            Assert.IsTrue(c1 == c2);\n        }\n\n        [TestMethod()]\n        public void SphereProjectionToPlaneTest()\n        {\n            Sphere s = new Sphere(new Point3d(-2, -2, -2), 5);\n            Plane3d p = new Plane3d(new Point3d(1, 1, 1), new Vector3d(1, 1, 1));\n            Circle3d c = s.ProjectionTo(p);\n            Circle3d res = new Circle3d(new Point3d(1, 1, 1), 5, new Vector3d(-1, -1, -1));\n            Assert.AreEqual(c, res);\n        }\n\n        [TestMethod()]\n        public void SphereProjectionToLineTest()\n        {\n            Sphere s = new Sphere(new Point3d(-4, -3, -2), 5);\n            Line3d l = new Line3d(new Point3d(0, 0, 0), new Vector3d(4, 3, 0));\n            Segment3d c = s.ProjectionTo(l);\n            Segment3d res = new Segment3d(new Point3d(0, 0, 0), new Point3d(-8, -6, 0));\n            Assert.AreEqual(c, res);\n        }\n\n        [TestMethod]\n        public void PointInSphereTest()\n        {\n            Point3d p = new Point3d(1, 1, 1);\n            Sphere s = new Sphere(p, 5);\n\n            p = new Point3d(2, 2, 2);  // Point inside\n            Assert.IsTrue(p.BelongsTo(s));\n            Assert.IsTrue(p.IsInside(s));\n            Assert.IsFalse(p.IsOutside(s));\n            Assert.IsFalse(p.IsOnBoundary(s));\n\n            p = new Point3d(1, 6, 1);  // Point on surface\n            Assert.IsTrue(p.BelongsTo(s));\n            Assert.IsFalse(p.IsInside(s));\n            Assert.IsFalse(p.IsOutside(s));\n            Assert.IsTrue(p.IsOnBoundary(s));\n\n            p = new Point3d(1, 6.005, 1);  // Point outside\n            Assert.IsFalse(p.BelongsTo(s));\n            Assert.IsFalse(p.IsInside(s));\n            Assert.IsTrue(p.IsOutside(s));\n            Assert.IsFalse(p.IsOnBoundary(s));\n        }\n\n        [TestMethod]\n        public void PointInSphereRelativeTest()\n        {\n            Point3d p = new Point3d(1, 1, 1);\n            Sphere s = new Sphere(p, 5);\n\n            double tol = GeometRi3D.Tolerance;\n            bool mode = GeometRi3D.UseAbsoluteTolerance;\n            GeometRi3D.Tolerance = 0.01;\n            GeometRi3D.UseAbsoluteTolerance = false;\n\n            p = new Point3d(1, 5.9, 1);  // Point inside\n            Assert.IsTrue(p.BelongsTo(s));\n            Assert.IsTrue(p.IsInside(s));\n            Assert.IsFalse(p.IsOutside(s));\n            Assert.IsFalse(p.IsOnBoundary(s));\n\n            p = new Point3d(1, 6.04, 1);  // Point on surface\n            Assert.IsTrue(p.BelongsTo(s));\n            Assert.IsFalse(p.IsInside(s));\n            Assert.IsFalse(p.IsOutside(s));\n            Assert.IsTrue(p.IsOnBoundary(s));\n\n            p = new Point3d(1, 6.06, 1);  // Point outside\n            Assert.IsFalse(p.BelongsTo(s));\n            Assert.IsFalse(p.IsInside(s));\n            Assert.IsTrue(p.IsOutside(s));\n            Assert.IsFalse(p.IsOnBoundary(s));\n\n            // Resore initial state\n            GeometRi3D.UseAbsoluteTolerance = mode;\n            GeometRi3D.Tolerance = tol;\n        }\n\n        [TestMethod]\n        public void SphereInBoxTest()\n        {\n            Box3d b = new Box3d(new Point3d(), 1.0, 1.0, 1.0);\n\n            Point3d p = new Point3d(5, 0, 0);\n            Sphere s = new Sphere(p, 0.1);\n            Assert.IsFalse(s.IsInside(b));\n\n            p = new Point3d(0.4, 0, 0);\n            s = new Sphere(p, 0.1);\n            Assert.IsFalse(s.IsInside(b));\n\n            p = new Point3d(0.3, 0, 0);\n            s = new Sphere(p, 0.1);\n            Assert.IsTrue(s.IsInside(b));\n        }\n\n        [TestMethod()]\n        public void SphereDistanceToSphereTest()\n        {\n            Sphere s1 = new Sphere(new Point3d(0, 0, 0), 1.0);\n            Point3d p1, p2;\n\n            // Intersecting objects\n            Sphere s2 = new Sphere(new Point3d(1, 0, 0), 1.0);\n            double dist = s1.DistanceTo(s2, out p1, out p2);\n            Assert.AreEqual(dist, 0.0);\n            Assert.AreEqual(p1, new Point3d(1, 0, 0));\n            Assert.AreEqual(p2, new Point3d(0, 0, 0));\n\n            // Touching objects\n            s2 = new Sphere(new Point3d(2, 0, 0), 1.0);\n            dist = s1.DistanceTo(s2, out p1, out p2);\n            Assert.AreEqual(dist, 0.0);\n            Assert.AreEqual(p1, new Point3d(1, 0, 0));\n            Assert.AreEqual(p2, new Point3d(1, 0, 0));\n\n\n            // Non-intersecting objects\n            s2 = new Sphere(new Point3d(3, 0, 0), 1.0);\n            dist = s1.DistanceTo(s2, out p1, out p2);\n            Assert.AreEqual(dist, 1.0);\n            Assert.AreEqual(p1, new Point3d(1, 0, 0));\n            Assert.AreEqual(p2, new Point3d(2, 0, 0));\n\n        }\n\n    }\n}\n"
  },
  {
    "path": "GeometRi.Tests/TetrahedronTest.cs",
    "content": "﻿using System;\nusing static System.Math;\nusing Microsoft.VisualStudio.TestTools.UnitTesting;\nusing GeometRi;\n\nnamespace GeometRi_Tests\n{\n    [TestClass]\n    public class TetrahedronTest\n    {\n        //===============================================================\n        // Tetrahedron tests\n        //===============================================================\n\n        [TestMethod()]\n        public void TetrahedronBasicTest()\n        {\n            Tetrahedron t = new Tetrahedron();\n\n            Assert.IsTrue(Abs(t.Volume - 1.0 / 3.0) < GeometRi3D.Tolerance);\n            Assert.IsTrue(Abs(t.Area - Sqrt(3) * 2) < GeometRi3D.Tolerance);\n        }\n\n        [TestMethod()]\n        public void TetrahedronPointLocationTest()\n        {\n            Tetrahedron t = new Tetrahedron();\n\n            Point3d p = new Point3d(0.5, 0.5, 0.5);  // Point inside\n            Assert.IsTrue(p.BelongsTo(t));\n            Assert.IsTrue(p.IsInside(t));\n            Assert.IsFalse(p.IsOutside(t));\n            Assert.IsFalse(p.IsOnBoundary(t));\n\n            p = new Point3d(0.0, 0.0, 0.0);  // Point on vertex\n            Assert.IsTrue(p.BelongsTo(t));\n            Assert.IsFalse(p.IsInside(t));\n            Assert.IsFalse(p.IsOutside(t));\n            Assert.IsTrue(p.IsOnBoundary(t));\n\n            p = new Point3d(0.5, 0.0, 0.5);  // Point on edge\n            Assert.IsTrue(p.BelongsTo(t));\n            Assert.IsFalse(p.IsInside(t));\n            Assert.IsFalse(p.IsOutside(t));\n            Assert.IsTrue(p.IsOnBoundary(t));\n\n            p = new Point3d(0.5, 0.25, 0.75);  // Point on face\n            Assert.IsTrue(p.BelongsTo(t));\n            Assert.IsFalse(p.IsInside(t));\n            Assert.IsFalse(p.IsOutside(t));\n            Assert.IsTrue(p.IsOnBoundary(t));\n\n            p = new Point3d(1, 1, 1);  // Point outside\n            Assert.IsFalse(p.BelongsTo(t));\n            Assert.IsFalse(p.IsInside(t));\n            Assert.IsTrue(p.IsOutside(t));\n            Assert.IsFalse(p.IsOnBoundary(t));\n\n        }\n\n        [TestMethod()]\n        public void TetrahedronClosestPointTest()\n        {\n            Tetrahedron t = new Tetrahedron();\n\n            Point3d p = new Point3d(0.5, 0.5, 0.5);  // Point inside\n            Point3d closest_point = t.ClosestPoint(p);\n            Assert.AreEqual(p, closest_point);\n\n            p = new Point3d(0.0, 0.0, 0.0);  // Point on vertex\n            closest_point = t.ClosestPoint(p);\n            Assert.AreEqual(p, closest_point);\n\n            p = new Point3d(0.5, 0.0, 0.5);  // Point on edge\n            closest_point = t.ClosestPoint(p);\n            Assert.AreEqual(p, closest_point);\n\n            p = new Point3d(0.5, 0.25, 0.75);  // Point on face\n            closest_point = t.ClosestPoint(p);\n            Assert.AreEqual(p, closest_point);\n\n            p = new Point3d(-1, -1, -1);  // Point outside\n            closest_point = t.ClosestPoint(p);\n            Assert.AreEqual(new Point3d(0,0,0), closest_point);\n\n            p = new Point3d(0.5, -1, 0.5);  // Point outside\n            closest_point = t.ClosestPoint(p);\n            Assert.AreEqual(new Point3d(0.5, 0, 0.5), closest_point);\n        }\n\n        [TestMethod()]\n        public void TetrahedronScaleTest()\n        {\n            Tetrahedron t = new Tetrahedron();\n            Tetrahedron s = t.Scale(0.5);\n\n            Assert.IsTrue(t.Center == s.Center);\n            Assert.IsTrue(Abs(t.Volume * 0.5 * 0.5 * 0.5 - s.Volume) < GeometRi3D.Tolerance);\n        }\n\n        [TestMethod()]\n        public void TetrahedronIntersectsTetrahedronTest_01()\n        {\n            Tetrahedron t = new Tetrahedron();\n            // tetrahedron inside\n            Tetrahedron s = t.Scale(0.5);\n            Assert.IsTrue(t.Intersects(s));\n            Assert.IsTrue(s.Intersects(t));\n        }\n\n        [TestMethod()]\n        public void TetrahedronIntersectsTetrahedronTest_02()\n        {\n            Tetrahedron t = new Tetrahedron();\n            // tetrahedron outside\n            Tetrahedron s = t.Scale(1.5);\n            Assert.IsTrue(t.Intersects(s));\n            Assert.IsTrue(s.Intersects(t));\n        }\n\n        [TestMethod()]\n        public void TetrahedronIntersectsTetrahedronTest_03()\n        {\n            Tetrahedron t = new Tetrahedron();\n            // vertex-to-vertex contact\n            Tetrahedron s = t.ReflectIn(new Point3d(0, 0, 0));\n            Assert.IsTrue(t.Intersects(s));\n            Assert.IsTrue(s.Intersects(t));\n        }\n\n        [TestMethod()]\n        public void TetrahedronIntersectsTetrahedronTest_04()\n        {\n            Tetrahedron t = new Tetrahedron();\n            // vertex-to-edge contact\n            Tetrahedron s = t.Translate(new Vector3d(-1, 0.5, -0.5));\n            Assert.IsTrue(t.Intersects(s));\n            Assert.IsTrue(s.Intersects(t));\n        }\n\n        [TestMethod()]\n        public void TetrahedronIntersectsTetrahedronTest_05()\n        {\n            Tetrahedron t = new Tetrahedron();\n            // edge-to-edge contact\n            Tetrahedron s = t.Translate(new Vector3d(-1, 0, 0));\n            Assert.IsTrue(t.Intersects(s));\n            Assert.IsTrue(s.Intersects(t));\n        }\n\n        [TestMethod()]\n        public void TetrahedronIntersectsTetrahedronTest_06()\n        {\n            Tetrahedron t = new Tetrahedron();\n            // face-to-face contact\n            Plane3d p = new Plane3d(new Point3d(1, 0, 1), new Vector3d(1, 1, 1));\n            Tetrahedron s = t.ReflectIn(p);\n            Assert.IsTrue(t.Intersects(s));\n            Assert.IsTrue(s.Intersects(t));\n        }\n\n        [TestMethod()]\n        public void TetrahedronIntersectsTetrahedronTest_07()\n        {\n            Tetrahedron t = new Tetrahedron();\n            // face-to-face partial contact\n            Plane3d p = new Plane3d(new Point3d(1, 0, 1), new Vector3d(1, 1, 1));\n            Tetrahedron s = t.ReflectIn(p);\n            Rotation r = new Rotation(new Vector3d(1, 1, 1), Math.PI / 6);\n            s.Rotate(r, s.Center);\n            Assert.IsTrue(t.Intersects(s));\n            Assert.IsTrue(s.Intersects(t));\n        }\n\n        [TestMethod()]\n        public void TetrahedronIntersectsTetrahedronTest_08()\n        {\n            Tetrahedron t = new Tetrahedron();\n            // vertex-to-face contact\n            Plane3d p = new Plane3d(new Point3d(1, 0, 1), new Vector3d(1, 1, 1));\n            Point3d projection = new Point3d(0, 0, 0).ProjectionTo(p);\n            Vector3d v = new Vector3d(new Point3d(0, 0, 0), projection);\n            Tetrahedron s = t.Translate(v);\n            Assert.IsTrue(t.Intersects(s));\n            Assert.IsTrue(s.Intersects(t));\n        }\n\n        [TestMethod()]\n        public void TetrahedronIntersectsTetrahedronTest_09()\n        {\n            Tetrahedron t = new Tetrahedron();\n            // one vertex inside\n            Plane3d p = new Plane3d(new Point3d(1, 0, 1), new Vector3d(1, 1, 1));\n            Point3d projection = new Point3d(0, 0, 0).ProjectionTo(p);\n            Vector3d v = new Vector3d(new Point3d(0, 0, 0), projection);\n            Tetrahedron s = t.Translate(0.9 * v);\n            Assert.IsTrue(t.Intersects(s));\n            Assert.IsTrue(s.Intersects(t));\n        }\n\n        [TestMethod()]\n        public void TetrahedronIntersectsTetrahedronTest_10()\n        {\n            Tetrahedron t = new Tetrahedron();\n            // not in contact\n            Plane3d p = new Plane3d(new Point3d(1, 0, 1), new Vector3d(1, 1, 1));\n            Point3d projection = new Point3d(0, 0, 0).ProjectionTo(p);\n            Vector3d v = new Vector3d(new Point3d(0, 0, 0), projection);\n            Tetrahedron s = t.Translate(1.1 * v);\n            Assert.IsFalse(t.Intersects(s));\n            Assert.IsFalse(s.Intersects(t));\n        }\n\n        [TestMethod()]\n        public void TetrahedronDistanceToTetrahedronTest_01()\n        {\n            Tetrahedron t = new Tetrahedron();\n            // tetrahedron inside\n            Tetrahedron s = t.Scale(0.5);\n            Assert.IsTrue(t.DistanceTo(s) == 0);\n            Assert.IsTrue(s.DistanceTo(t) == 0);\n        }\n\n        [TestMethod()]\n        public void TetrahedronDistanceToTetrahedronTest_02()\n        {\n            Tetrahedron t = new Tetrahedron();\n            // tetrahedron outside\n            Tetrahedron s = t.Scale(1.5);\n            Assert.IsTrue(t.DistanceTo(s) == 0);\n            Assert.IsTrue(s.DistanceTo(t) == 0);\n        }\n\n        [TestMethod()]\n        public void TetrahedronDistanceToTetrahedronTest_03()\n        {\n            Tetrahedron t = new Tetrahedron();\n            // vertex-to-vertex contact\n            Tetrahedron s = t.ReflectIn(new Point3d(0, 0, 0));\n            Assert.IsTrue(t.DistanceTo(s) == 0);\n            Assert.IsTrue(s.DistanceTo(t) == 0);\n        }\n\n        [TestMethod()]\n        public void TetrahedronDistanceToTetrahedronTest_04()\n        {\n            Tetrahedron t = new Tetrahedron();\n            // vertex-to-edge contact\n            Tetrahedron s = t.Translate(new Vector3d(-1, 0.5, -0.5));\n            Assert.IsTrue(t.DistanceTo(s) == 0);\n            Assert.IsTrue(s.DistanceTo(t) == 0);\n        }\n\n        [TestMethod()]\n        public void TetrahedronDistanceToTetrahedronTest_05()\n        {\n            Tetrahedron t = new Tetrahedron();\n            // edge-to-edge contact\n            Tetrahedron s = t.Translate(new Vector3d(-1, 0, 0));\n            Assert.IsTrue(t.DistanceTo(s) == 0);\n            Assert.IsTrue(s.DistanceTo(t) == 0);\n        }\n\n        [TestMethod()]\n        public void TetrahedronDistanceToTetrahedronTest_06()\n        {\n            Tetrahedron t = new Tetrahedron();\n            // face-to-face contact\n            Plane3d p = new Plane3d(new Point3d(1, 0, 1), new Vector3d(1, 1, 1));\n            Tetrahedron s = t.ReflectIn(p);\n            Assert.IsTrue(t.DistanceTo(s) == 0);\n            Assert.IsTrue(s.DistanceTo(t) == 0);\n        }\n\n        [TestMethod()]\n        public void TetrahedronDistanceToTetrahedronTest_07()\n        {\n            Tetrahedron t = new Tetrahedron();\n            // face-to-face partial contact\n            Plane3d p = new Plane3d(new Point3d(1, 0, 1), new Vector3d(1, 1, 1));\n            Tetrahedron s = t.ReflectIn(p);\n            Rotation r = new Rotation(new Vector3d(1, 1, 1), Math.PI / 6);\n            s.Rotate(r, s.Center);\n            Assert.IsTrue(t.DistanceTo(s) == 0);\n            Assert.IsTrue(s.DistanceTo(t) == 0);\n        }\n\n        [TestMethod()]\n        public void TetrahedronDistanceToTetrahedronTest_08()\n        {\n            Tetrahedron t = new Tetrahedron();\n            // vertex-to-face contact\n            Plane3d p = new Plane3d(new Point3d(1, 0, 1), new Vector3d(1, 1, 1));\n            Point3d projection = new Point3d(0, 0, 0).ProjectionTo(p);\n            Vector3d v = new Vector3d(new Point3d(0, 0, 0), projection);\n            Tetrahedron s = t.Translate(v);\n            Assert.IsTrue(t.DistanceTo(s) == 0);\n            Assert.IsTrue(s.DistanceTo(t) == 0);\n        }\n\n        [TestMethod()]\n        public void TetrahedronDistanceToTetrahedronTest_09()\n        {\n            Tetrahedron t = new Tetrahedron();\n            // one vertex inside\n            Plane3d p = new Plane3d(new Point3d(1, 0, 1), new Vector3d(1, 1, 1));\n            Point3d projection = new Point3d(0, 0, 0).ProjectionTo(p);\n            Vector3d v = new Vector3d(new Point3d(0, 0, 0), projection);\n            Tetrahedron s = t.Translate(0.9 * v);\n            Assert.IsTrue(t.DistanceTo(s) == 0);\n            Assert.IsTrue(s.DistanceTo(t) == 0);\n        }\n\n        [TestMethod()]\n        public void TetrahedronDistanceToTetrahedronTest_10()\n        {\n            Tetrahedron t = new Tetrahedron();\n            // not in contact\n            Vector3d v = new Vector3d(2,0,0);\n            Tetrahedron s = t.Translate(v);\n            Assert.IsTrue(Abs(t.DistanceTo(s) - 1) < GeometRi3D.Tolerance);\n            Assert.IsTrue(Abs(s.DistanceTo(t) - 1) < GeometRi3D.Tolerance);\n        }\n\n        [TestMethod()]\n        public void TetrahedronDistanceToTetrahedronTest_11()\n        {\n            Tetrahedron t = new Tetrahedron();\n            // in contact\n            Tetrahedron s = t.ReflectIn(t.Center);\n            s = s.Scale(1.1);\n            Assert.IsTrue(Abs(t.DistanceTo(s) - 0) < GeometRi3D.Tolerance);\n            Assert.IsTrue(Abs(s.DistanceTo(t) - 0) < GeometRi3D.Tolerance);\n        }\n\n        [TestMethod()]\n        public void TetrahedronDistanceToTetrahedronTest_12()\n        {\n            Point3d p0 = new Point3d(1.18847041209228, 0.104193542059284, 0.35298291672622 );\n            Point3d p1 = new Point3d(0.649467768945706, 0.170331494522815, 0.72174959083238 );\n            Point3d p2 = new Point3d(1.15947687723363, 0.573922428456402, 0.810586551138034 );\n            Point3d p3 = new Point3d(0.793812982683988, 0.621719485201377, 0.267546685570428 );\n            Tetrahedron t1 = new Tetrahedron(p0, p1, p2, p3);\n\n            Point3d s0 = new Point3d(0.216267039810085, 0.169909202890096, 0.859064204525464);\n            Point3d s1 = new Point3d(0.205044294164905, 0.659002041871181, 0.42140088318818);\n            Point3d s2 = new Point3d(0.66494259923399, 0.648073860241189, 0.889654085897164);\n            Point3d s3 = new Point3d(0.684153131501953, 0.210778895931041, 0.400480284835266);\n            Tetrahedron t2 = new Tetrahedron(s0, s1, s2, s3);\n\n            double dist = t1.DistanceTo(t2);\n            double dist2 = t2.DistanceTo(t1);\n\n            Assert.IsTrue(dist > 0.02562);\n            Assert.IsTrue(dist2 > 0.02562);\n\n            Assert.IsFalse(t1.Intersects(t2));\n            Assert.IsFalse(t2.Intersects(t1));\n        }\n\n        [TestMethod()]\n        public void TetrahedronAABBTest()\n        {\n            Tetrahedron t = new Tetrahedron();\n\n            Box3d aabb = t.BoundingBox();\n\n            Assert.IsTrue(aabb.Center == new Point3d(0.5, 0.5, 0.5));\n            Assert.IsTrue(Abs(aabb.L1 - 1) < GeometRi3D.Tolerance);\n            Assert.IsTrue(Abs(aabb.L2 - 1) < GeometRi3D.Tolerance);\n            Assert.IsTrue(Abs(aabb.L3 - 1) < GeometRi3D.Tolerance);\n        }\n\n        [TestMethod()]\n        public void TetrahedronAABBTest_01()\n        {\n            Tetrahedron t = new Tetrahedron().Translate(new Vector3d(-1,0,0));\n\n            Box3d aabb = t.BoundingBox();\n\n            Assert.IsTrue(aabb.Center == new Point3d(-0.5, 0.5, 0.5));\n            Assert.IsTrue(Abs(aabb.L1 - 1) < GeometRi3D.Tolerance);\n            Assert.IsTrue(Abs(aabb.L2 - 1) < GeometRi3D.Tolerance);\n            Assert.IsTrue(Abs(aabb.L3 - 1) < GeometRi3D.Tolerance);\n        }\n\n    }\n}\n"
  },
  {
    "path": "GeometRi.Tests/TranslateTest.cs",
    "content": "﻿using System;\nusing static System.Math;\nusing Microsoft.VisualStudio.TestTools.UnitTesting;\nusing GeometRi;\n\nnamespace GeometRi_Tests\n{\n    [TestClass]\n    public class TranslateTest\n    {\n        //===============================================================\n        // Object translate tests\n        //===============================================================\n\n        [TestMethod()]\n        public void TranslatePointTest1()\n        {\n            Coord3d coord1 = Coord3d.GlobalCS.Copy();\n            coord1.RotateDeg(new Vector3d(0, 0, 1), 90);\n            coord1.Origin = new Point3d(1, 1, 1);\n\n            Point3d p1 = new Point3d(1, 2, 3, Coord3d.GlobalCS);\n            Vector3d v1 = new Vector3d(1, 1, 1, coord1);\n\n            Assert.IsTrue(p1.Translate(v1) == new Point3d(0, 3, 4));\n        }\n\n        [TestMethod()]\n        public void TranslatePointTest()\n        {\n            Coord3d coord1 = Coord3d.GlobalCS.Copy();\n            Coord3d coord2 = Coord3d.GlobalCS.Copy();\n            coord1.RotateDeg(new Vector3d(1, 2, 3), 90);\n            coord2.RotateDeg(new Vector3d(1, 1, 1), 120);\n            coord1.Origin = new Point3d(1, 1, 1);\n            coord2.Origin = new Point3d(10, 2, 5);\n\n            Point3d p1 = new Point3d(1, 2, 3, Coord3d.GlobalCS);\n            Point3d p2 = new Point3d(10, -2, 6, coord1);\n            Point3d p3 = new Point3d(-3, 5, 1, coord2);\n            Vector3d v1 = new Vector3d(p1, p2);\n            Vector3d v2 = new Vector3d(p2, p3);\n            Vector3d v3 = new Vector3d(p3, p1);\n\n            Point3d p = new Point3d(5, 6, 7);\n\n            Assert.IsTrue(p.Translate(v1).Translate(v2).Translate(v3) == p);\n        }\n\n        [TestMethod()]\n        public void TranslatePlaneTest()\n        {\n            Coord3d coord1 = Coord3d.GlobalCS.Copy();\n            Coord3d coord2 = Coord3d.GlobalCS.Copy();\n            coord1.RotateDeg(new Vector3d(1, 2, 3), 90);\n            coord2.RotateDeg(new Vector3d(1, 1, 1), 120);\n            coord1.Origin = new Point3d(1, 1, 1);\n            coord2.Origin = new Point3d(10, 2, 5);\n\n            Point3d p1 = new Point3d(1, 2, 3, Coord3d.GlobalCS);\n            Point3d p2 = new Point3d(10, -2, 6, coord1);\n            Point3d p3 = new Point3d(-3, 5, 1, coord2);\n            Vector3d v1 = new Vector3d(p1, p2);\n            Vector3d v2 = new Vector3d(p2, p3);\n            Vector3d v3 = new Vector3d(p3, p1);\n\n            Plane3d s = new Plane3d(1, 2, 3, 4);\n\n            Assert.IsTrue(s.Translate(v1).Translate(v2).Translate(v3) == s);\n        }\n    }\n}\n"
  },
  {
    "path": "GeometRi.Tests/TriangleIntersectionWithLineSegmentTests.cs",
    "content": "﻿using System;\nusing static System.Math;\nusing Microsoft.VisualStudio.TestTools.UnitTesting;\nusing GeometRi;\n\nnamespace GeometRi.Tests\n{\n    [TestClass]\n    public class TriangleIntersectionWithLineSegmentTests\n    {\n\n\n        [TestMethod]\n        public void TriangleNone()\n        {\n            var lineSegment = new Segment3d(new Point3d(2, 2, -1), new Point3d(2, 2, 1));\n            var triangle = new Triangle(\n                new Point3d(0, 0, 0),\n                new Point3d(0, 2, 0),\n                new Point3d(2, 0, 0));\n\n            var intersection = triangle.IntersectionWith(lineSegment) as Point3d;\n\n            Assert.AreEqual(null, intersection);\n        }\n\n        [TestMethod]\n        public void TriangleStraight()\n        {\n            var lineSegment = new Segment3d(new Point3d(1, 1, -1), new Point3d(1, 1, 1));\n            var triangle = new Triangle(\n                new Point3d(0, 0, 0),\n                new Point3d(0, 2, 0),\n                new Point3d(2, 0, 0));\n\n            var intersection = triangle.IntersectionWith(lineSegment) as Point3d;\n\n            Assert.AreEqual(new Point3d(1, 1, 0), intersection);\n        }\n\n        [TestMethod]\n        public void TriangleSkewedTriangle()\n        {\n            var lineSegment = new Segment3d(new Point3d(1, 1, -1), new Point3d(1, 1, 1));\n            var triangle = new Triangle(\n                new Point3d(0, 0, 1),\n                new Point3d(0, 2, -1),\n                new Point3d(2, 0, 0));\n\n            var intersection = triangle.IntersectionWith(lineSegment) as Point3d;\n\n            Assert.AreEqual(new Point3d(1, 1, -0.5), intersection);\n        }\n\n        [TestMethod]\n        public void TriangleSkewedLine()\n        {\n            var lineSegment = new Segment3d(new Point3d(.7, 0.6, -1), new Point3d(1, 1, 1));\n            var triangle = new Triangle(\n                new Point3d(0, 0, 0),\n                new Point3d(0, 2, 0),\n                new Point3d(2, 0, 0));\n\n            var intersection = triangle.IntersectionWith(lineSegment) as Point3d;\n\n            Assert.AreEqual(new Point3d(0.85, 0.8, 0), intersection);\n        }\n\n        [TestMethod]\n        public void TriangleSkewed()\n        {\n            var lineSegment = new Segment3d(new Point3d(.7, 0.6, -1), new Point3d(1, 1, 1));\n            var triangle = new Triangle(\n                new Point3d(0, 0, 1),\n                new Point3d(0, 2, -1),\n                new Point3d(2, 0, 0));\n\n            var intersection = triangle.IntersectionWith(lineSegment) as Point3d;\n\n            var expected = new Point3d(0.82352941176470584, 0.76470588235294112, -0.17647058823529405);\n            double dist = expected.DistanceTo(intersection);\n            Assert.IsTrue(GeometRi3D.AlmostEqual(dist, 0));\n        }\n\n        [TestMethod]\n        public void TriangleSegment()\n        {\n            var lineSegment = new Segment3d(new Point3d(0, 0, 0), new Point3d(1, 1, 0));\n            var triangle = new Triangle(\n                new Point3d(0, 0, 0),\n                new Point3d(0, 2, 0),\n                new Point3d(2, 0, 0));\n\n            var intersection = triangle.IntersectionWith(lineSegment) as Segment3d;\n\n            Assert.AreEqual(intersection, new Segment3d(\n                new Point3d(0, 0, 0),\n                new Point3d(1, 1, 0)));\n        }\n\n        [TestMethod]\n        public void TriangleSegmentPartial()\n        {\n            var lineSegment = new Segment3d(new Point3d(-1, 0, 0), new Point3d(1, 3, 0));\n            var triangle = new Triangle(\n                new Point3d(0, 0, 0),\n                new Point3d(0, 2, 0),\n                new Point3d(2, 0, 0));\n\n            var intersection = triangle.IntersectionWith(lineSegment) as Segment3d;\n\n            Assert.AreEqual(intersection, new Segment3d(\n                new Point3d(0, 1.5, 0),\n                new Point3d(0.2, 1.8, 0)));\n        }\n\n        [TestMethod]\n        public void TriangleSegmentAB()\n        {\n            var lineSegment = new Segment3d(new Point3d(.5, .5, 0), new Point3d(.5, -.5, 0));\n            var triangle = new Triangle(\n                new Point3d(0, 0, 0),\n                new Point3d(1, 0, 0),\n                new Point3d(0, 1, 0));\n\n            var intersectionWith = triangle.IntersectionWith(lineSegment);\n            Assert.IsTrue(intersectionWith is Segment3d);\n\n            var intersection = intersectionWith as Segment3d;\n            Assert.AreEqual(intersection, new Segment3d(\n                new Point3d(.5, .5, 0),\n                new Point3d(.5, 0, 0)));\n        }\n\n        [TestMethod]\n        public void TriangleSegmentCAMiddleOfAB_BC()\n        {\n            var lineSegment = new Segment3d(new Point3d(0.75, 0.25, 0), new Point3d(0, 1, 0));\n            var triangle = new Triangle(\n                new Point3d(0, 0, 0),\n                new Point3d(1, 0, 0),\n                new Point3d(1, 1, 0));\n\n            var intersectionWith = triangle.IntersectionWith(lineSegment);\n            Assert.IsTrue(intersectionWith is Segment3d);\n\n            var intersection = intersectionWith as Segment3d;\n            Assert.AreEqual(intersection, new Segment3d(\n                new Point3d(0.75, 0.25, 0),\n                new Point3d(.5, .5, 0)));\n        }\n\n        [TestMethod]\n        public void TriangleSegmentCA()\n        {\n            var lineSegment = new Segment3d(new Point3d(1.1, 0, 0), new Point3d(0, 1.1, 0));\n            var triangle = new Triangle(\n                new Point3d(0.25, -0.25, 0),\n                new Point3d(1.25, -0.25, 0),\n                new Point3d(1.25, 0.75, 0));\n\n            var intersectionWith = triangle.IntersectionWith(lineSegment);\n            Assert.IsTrue(intersectionWith is Segment3d);\n\n            var intersection = intersectionWith as Segment3d;\n            Assert.AreEqual(intersection, new Segment3d(\n                new Point3d(1.1, 0, 0),\n                new Point3d(.8, .3, 0)));\n        }\n    }\n}\n"
  },
  {
    "path": "GeometRi.Tests/TriangleTest.cs",
    "content": "﻿using System;\nusing static System.Math;\nusing Microsoft.VisualStudio.TestTools.UnitTesting;\nusing GeometRi;\n\nnamespace GeometRi_Tests\n{\n    [TestClass]\n    public class TriangleTest\n    {\n        //===============================================================\n        // Triangle tests\n        //===============================================================\n\n        [TestMethod()]\n        public void TriangleEqualTest()\n        {\n            Point3d p1 = new Point3d(-3, 0, 4);\n            Point3d p2 = new Point3d(4, 0, 5);\n            Point3d p3 = new Point3d(1, 0, -4);\n\n            Triangle t1 = new Triangle(p1, p2, p3);\n            Triangle t2 = new Triangle(p1, p3, p2);\n            Triangle t3 = new Triangle(p3, p2, p1);\n\n            Assert.AreEqual(t1, t2);\n            Assert.AreEqual(t1, t3);\n            Assert.AreEqual(t3, t2);\n        }\n\n        [TestMethod()]\n        public void TriangleAreaTest()\n        {\n            Point3d p1 = new Point3d(0, 0, 0);\n            Point3d p2 = new Point3d(1, 0, 0);\n            Point3d p3 = new Point3d(0, 1, 0);\n\n            Triangle t = new Triangle(p1, p2, p3);\n            Assert.IsTrue(Abs(t.Area - 0.5) < GeometRi3D.Tolerance);\n        }\n\n        [TestMethod()]\n        public void TriangleBisectorTest()\n        {\n            Point3d p1 = new Point3d(0, 0, 0);\n            Point3d p2 = new Point3d(1, 0, 0);\n            Point3d p3 = new Point3d(0, 1, 0);\n            Triangle t = new Triangle(p1, p2, p3);\n            Assert.AreEqual(t.Bisector_A, new Segment3d(p1, new Point3d(0.5, 0.5, 0)));\n\n            t = new Triangle(p2, p3, p1);\n            Assert.AreEqual(t.Bisector_C, new Segment3d(p1, new Point3d(0.5, 0.5, 0)));\n\n            t = new Triangle(p3, p1, p2);\n            Assert.AreEqual(t.Bisector_B, new Segment3d(p1, new Point3d(0.5, 0.5, 0)));\n        }\n\n        [TestMethod()]\n        public void TriangleExternalBisectorTest()\n        {\n            Point3d p1 = new Point3d(0, 1, 0);\n            Point3d p2 = new Point3d(1, 0, 0);\n            Point3d p3 = new Point3d(-1, 0, 0);\n            Line3d line = new Line3d(p1, new Vector3d(1, 0, 0));\n\n            Triangle t = new Triangle(p1, p2, p3);\n            Assert.AreEqual(t.ExternalBisector_A, line);\n\n            t = new Triangle(p2, p1, p3);\n            Assert.AreEqual(t.ExternalBisector_B, line);\n\n            t = new Triangle(p3, p2, p1);\n            Assert.AreEqual(t.ExternalBisector_C, line);\n        }\n\n        [TestMethod()]\n        public void TriangleIncenterTest()\n        {\n            Point3d p1 = new Point3d(0, 0, 0);\n            Point3d p2 = new Point3d(14, 0, 0);\n            Point3d p3 = new Point3d(5, 12, 0);\n\n            Triangle t = new Triangle(p1, p2, p3);\n            Assert.AreEqual(t.Incenter, new Point3d(6, 4, 0));\n        }\n\n        [TestMethod()]\n        public void TriangleOrthocenterTest()\n        {\n            Point3d p1 = new Point3d(0, 0, 0);\n            Point3d p2 = new Point3d(14, 0, 0);\n            Point3d p3 = new Point3d(5, 1, 0);\n\n            Triangle t = new Triangle(p1, p2, p3);\n            Assert.AreEqual(t.Orthocenter, new Point3d(5, 45, 0));\n        }\n\n        [TestMethod()]\n        public void TriangleCentroidTest()\n        {\n            Point3d p1 = new Point3d(0, 0, 0);\n            Point3d p2 = new Point3d(14, 0, 0);\n            Point3d p3 = new Point3d(4, 12, 0);\n\n            Triangle t = new Triangle(p1, p2, p3);\n            Assert.AreEqual(t.Centroid, new Point3d(6, 4, 0));\n        }\n\n        [TestMethod()]\n        public void TriangleCircumcenterTest()\n        {\n            Point3d p1 = new Point3d(0, 0, 0);\n            Point3d p2 = new Point3d(14, 0, 0);\n            Point3d p3 = new Point3d(4, 12, 0);\n\n            Triangle t = new Triangle(p1, p2, p3);\n            Assert.AreEqual(t.Circumcenter, new Point3d(7.0, 13.0 / 3, 0.0));\n        }\n\n        [TestMethod()]\n        public void TriangleGeometryTest()\n        {\n            Point3d p1 = new Point3d(0, 0, 0);\n            Point3d p2 = new Point3d(6, 0, 0);\n            Point3d p3 = new Point3d(3, 6, 0);\n\n            Triangle t = new Triangle(p1, p2, p3);\n            Assert.IsTrue(t.IsAcute);\n            Assert.IsTrue(t.IsIsosceles);\n\n            t.C = new Point3d(3, 2, 0);\n            Assert.IsTrue(t.IsObtuse);\n\n            t.C = new Point3d(2, 2, 0);\n            Assert.IsTrue(t.IsScalene);\n\n            t.C = new Point3d(0, 2, 0);\n            Assert.IsTrue(t.IsRight);\n        }\n\n        [TestMethod]\n        public void PointInTriangleTest()\n        {\n            Point3d a = new Point3d(0, 0, 0);\n            Point3d b = new Point3d(15, 0, 0);\n            Point3d p = new Point3d(0, 15, 0);\n            Triangle s = new Triangle(a, b, p);\n\n            p = new Point3d(1, 1, 0);  // Point inside\n            Assert.IsTrue(p.BelongsTo(s));\n            Assert.IsTrue(p.IsInside(s));\n            Assert.IsFalse(p.IsOutside(s));\n            Assert.IsFalse(p.IsOnBoundary(s));\n\n            p = new Point3d(10, 0, 0);  // Point on boundary\n            Assert.IsTrue(p.BelongsTo(s));\n            Assert.IsFalse(p.IsInside(s));\n            Assert.IsFalse(p.IsOutside(s));\n            Assert.IsTrue(p.IsOnBoundary(s));\n\n            p = new Point3d(1, 3, 1);  // Point outside\n            Assert.IsFalse(p.BelongsTo(s));\n            Assert.IsFalse(p.IsInside(s));\n            Assert.IsTrue(p.IsOutside(s));\n            Assert.IsFalse(p.IsOnBoundary(s));\n\n            p = new Point3d(16, 0, 0);  // Point outside\n            Assert.IsFalse(p.BelongsTo(s));\n            Assert.IsFalse(p.IsInside(s));\n            Assert.IsTrue(p.IsOutside(s));\n            Assert.IsFalse(p.IsOnBoundary(s));\n        }\n\n        [TestMethod]\n        public void PointInsideRelativeTest()\n        {\n            Point3d a = new Point3d(0, 0, 0);\n            Point3d b = new Point3d(15, 0, 0);\n            Point3d p = new Point3d(0, 15, 0);\n            Triangle s = new Triangle(a, b, p);\n\n            double tol = GeometRi3D.Tolerance;\n            bool mode = GeometRi3D.UseAbsoluteTolerance;\n            GeometRi3D.Tolerance = 0.01;\n            GeometRi3D.UseAbsoluteTolerance = false;\n\n            p = new Point3d(1, 1, 0.1);  // Point inside\n            Assert.IsTrue(p.BelongsTo(s));\n            Assert.IsTrue(p.IsInside(s));\n            Assert.IsFalse(p.IsOutside(s));\n            Assert.IsFalse(p.IsOnBoundary(s));\n\n            p = new Point3d(0.2, 5, 0.0);  // Point inside\n            Assert.IsTrue(p.BelongsTo(s));\n            Assert.IsTrue(p.IsInside(s));\n            Assert.IsFalse(p.IsOutside(s));\n            Assert.IsFalse(p.IsOnBoundary(s));\n\n            // Resore initial state\n            GeometRi3D.UseAbsoluteTolerance = mode;\n            GeometRi3D.Tolerance = tol;\n        }\n\n        [TestMethod]\n        public void PointOnBoundaryRelativeTest()\n        {\n            Point3d a = new Point3d(0, 0, 0);\n            Point3d b = new Point3d(15, 0, 0);\n            Point3d p = new Point3d(0, 15, 0);\n            Triangle s = new Triangle(a, b, p);\n\n            double tol = GeometRi3D.Tolerance;\n            bool mode = GeometRi3D.UseAbsoluteTolerance;\n            GeometRi3D.Tolerance = 0.01;\n            GeometRi3D.UseAbsoluteTolerance = false;\n\n            p = new Point3d(10, 0.1, 0);  // Point on boundary\n            Assert.IsTrue(p.BelongsTo(s));\n            Assert.IsFalse(p.IsInside(s));\n            Assert.IsFalse(p.IsOutside(s));\n            Assert.IsTrue(p.IsOnBoundary(s));\n\n            p = new Point3d(0.1, 0.1, 0);  // Point on boundary\n            Assert.IsTrue(p.BelongsTo(s));\n            Assert.IsFalse(p.IsInside(s));\n            Assert.IsFalse(p.IsOutside(s));\n            Assert.IsTrue(p.IsOnBoundary(s));\n\n            p = new Point3d(-0.1, -0.1, 0);  // Point on boundary\n            Assert.IsTrue(p.BelongsTo(s));\n            Assert.IsFalse(p.IsInside(s));\n            Assert.IsFalse(p.IsOutside(s));\n            Assert.IsTrue(p.IsOnBoundary(s));\n\n            p = new Point3d(7.6, 7.6, 0);  // Point on boundary\n            Assert.IsTrue(p.BelongsTo(s));\n            Assert.IsFalse(p.IsInside(s));\n            Assert.IsFalse(p.IsOutside(s));\n            Assert.IsTrue(p.IsOnBoundary(s));\n\n            // Resore initial state\n            GeometRi3D.UseAbsoluteTolerance = mode;\n            GeometRi3D.Tolerance = tol;\n        }\n\n        [TestMethod]\n        public void PointOutsideRelativeTest()\n        {\n            Point3d a = new Point3d(0, 0, 0);\n            Point3d b = new Point3d(15, 0, 0);\n            Point3d p = new Point3d(0, 15, 0);\n            Triangle s = new Triangle(a, b, p);\n\n            double tol = GeometRi3D.Tolerance;\n            bool mode = GeometRi3D.UseAbsoluteTolerance;\n            GeometRi3D.Tolerance = 0.01;\n            GeometRi3D.UseAbsoluteTolerance = false;\n\n            p = new Point3d(1, 1, 0.2);  // Point outside\n            Assert.IsFalse(p.BelongsTo(s));\n            Assert.IsFalse(p.IsInside(s));\n            Assert.IsTrue(p.IsOutside(s));\n            Assert.IsFalse(p.IsOnBoundary(s));\n\n            p = new Point3d(15.2, 0, 0);  // Point outside\n            Assert.IsFalse(p.BelongsTo(s));\n            Assert.IsFalse(p.IsInside(s));\n            Assert.IsTrue(p.IsOutside(s));\n            Assert.IsFalse(p.IsOnBoundary(s));\n\n            p = new Point3d(7.65, 7.65, 0);  // Point outside\n            Assert.IsFalse(p.BelongsTo(s));\n            Assert.IsFalse(p.IsInside(s));\n            Assert.IsTrue(p.IsOutside(s));\n            Assert.IsFalse(p.IsOnBoundary(s));\n\n            p = new Point3d(-0.2, 10, 0);  // Point outside\n            Assert.IsFalse(p.BelongsTo(s));\n            Assert.IsFalse(p.IsInside(s));\n            Assert.IsTrue(p.IsOutside(s));\n            Assert.IsFalse(p.IsOnBoundary(s));\n\n            // Resore initial state\n            GeometRi3D.UseAbsoluteTolerance = mode;\n            GeometRi3D.Tolerance = tol;\n        }\n\n        [TestMethod()]\n        public void TriangleIntersectionWithLineTest()\n        {\n            Point3d p1 = new Point3d(0, 0, 0);\n            Point3d p2 = new Point3d(6, 0, 0);\n            Point3d p3 = new Point3d(0, 6, 0);\n\n            Triangle t = new Triangle(p1, p2, p3);\n\n            // Line coincides with one side\n            Line3d l = new Line3d(new Point3d(), new Vector3d(1, 0, 0));\n            Assert.IsTrue((Segment3d)t.IntersectionWith(l) == new Segment3d(p1, p2));\n\n            // Line crosses one corner\n            l = new Line3d(new Point3d(), new Vector3d(1, -1, 0));\n            Assert.IsTrue((Point3d)t.IntersectionWith(l) == p1);\n\n            // Line crosses one corner and one side\n            l = new Line3d(new Point3d(), new Vector3d(1, 1, 0));\n            Assert.IsTrue((Segment3d)t.IntersectionWith(l) == new Segment3d(p1, new Point3d(3, 3, 0)));\n\n            // Line crosses two sides\n            l = new Line3d(new Point3d(0, 3, 0), new Vector3d(1, -1, 0));\n            Assert.IsTrue((Segment3d)t.IntersectionWith(l) == new Segment3d(new Point3d(0, 3, 0), new Point3d(3, 0, 0)));\n\n            // Line crosses triangle\n            l = new Line3d(new Point3d(1, 1, 1), new Vector3d(0, 0, 1));\n            Assert.IsTrue((Point3d)t.IntersectionWith(l) == new Point3d(1, 1, 0));\n\n            // Line crosses corner\n            l = new Line3d(new Point3d(0, 0, 1), new Vector3d(0, 0, 1));\n            Assert.IsTrue((Point3d)t.IntersectionWith(l) == p1);\n\n            l = new Line3d(new Point3d(-10, -10, 1), new Vector3d(0, 0, 1));\n            Assert.IsNull(t.IntersectionWith(l));\n\n        }\n\n        [TestMethod()]\n        public void TriangleIntersectionWithLineRelativeTest()\n        {\n\n            double tol = GeometRi3D.Tolerance;\n            bool mode = GeometRi3D.UseAbsoluteTolerance;\n            GeometRi3D.Tolerance = 0.01;\n            GeometRi3D.UseAbsoluteTolerance = false;\n\n            Point3d p1 = new Point3d(0, 0, 0);\n            Point3d p2 = new Point3d(6, 0, 0);\n            Point3d p3 = new Point3d(0, 6, 0);\n\n            Triangle t = new Triangle(p1, p2, p3);\n\n            // Line coincides with one side\n            Line3d l = new Line3d(new Point3d(0, 0, 0.01), new Vector3d(1, 0, 0));\n            Assert.IsTrue((Segment3d)t.IntersectionWith(l) == new Segment3d(p1, p2));\n\n            // Line crosses one corner and one side\n            l = new Line3d(new Point3d(), new Vector3d(1, 1, 0.001));\n            Assert.IsTrue((Segment3d)t.IntersectionWith(l) == new Segment3d(p1, new Point3d(3, 3, 0)));\n\n\n            // Resore initial state\n            GeometRi3D.UseAbsoluteTolerance = mode;\n            GeometRi3D.Tolerance = tol;\n        }\n\n        [TestMethod()]\n        public void TriangleIntersectionWithPlaneTest()\n        {\n            Point3d p1 = new Point3d(0, 0, 0);\n            Point3d p2 = new Point3d(6, 0, 0);\n            Point3d p3 = new Point3d(0, 6, 0);\n\n            Triangle t = new Triangle(p1, p2, p3);\n\n            // Plane is parallel\n            Plane3d s = new Plane3d(new Point3d(0, 0, 1), new Vector3d(0, 0, 1));\n            Assert.IsNull(t.IntersectionWith(s));\n\n            s = new Plane3d(new Point3d(), new Vector3d(0, 0, 1));\n            Assert.IsTrue((Triangle)t.IntersectionWith(s) == t);\n\n            // Plane crosses triangle\n            p1 = new Point3d(0, 0, 0);\n            p2 = new Point3d(6, 0, 1);\n            p3 = new Point3d(0, 6, -1);\n\n            t = new Triangle(p1, p2, p3);\n            Assert.IsTrue((Segment3d)t.IntersectionWith(s) == new Segment3d(p1, new Point3d(3, 3, 0)));\n        }\n\n        [TestMethod()]\n        public void TriangleIntersectionWithPlaneRelativeTest_01()\n        {\n\n            double tol = GeometRi3D.Tolerance;\n            bool mode = GeometRi3D.UseAbsoluteTolerance;\n            GeometRi3D.Tolerance = 0.01;\n            GeometRi3D.UseAbsoluteTolerance = false;\n\n            Point3d p1 = new Point3d(0, 0, 0);\n            Point3d p2 = new Point3d(6, 0, 0);\n            Point3d p3 = new Point3d(0, 6, 0);\n\n            Triangle t = new Triangle(p1, p2, p3);\n\n            Plane3d s = new Plane3d(new Point3d(), new Vector3d(0.001, 0, 1));\n            Assert.IsTrue((Triangle)t.IntersectionWith(s) == t);\n\n\n            // Resore initial state\n            GeometRi3D.UseAbsoluteTolerance = mode;\n            GeometRi3D.Tolerance = tol;\n        }\n\n        [TestMethod()]\n        public void TriangleIntersectionWithPlaneRelativeTest_02()\n        {\n\n            double tol = GeometRi3D.Tolerance;\n            bool mode = GeometRi3D.UseAbsoluteTolerance;\n            GeometRi3D.Tolerance = 0.001;\n            GeometRi3D.UseAbsoluteTolerance = false;\n\n            Plane3d s = new Plane3d(new Point3d(), new Vector3d(0.001, 0, 1));\n\n            // Plane crosses triangle\n            Point3d p1 = new Point3d(0, 0, 0);\n            Point3d p2 = new Point3d(6, 0.01, 1);\n            Point3d p3 = new Point3d(0, 6, -1);\n\n            Triangle t = new Triangle(p1, p2, p3);\n            var intersection_res = t.IntersectionWith(s);\n            //Assert.IsTrue(intersection_res == new Segment3d(p1, new Point3d(3, 3, 0)));\n\n            // Resore initial state\n            GeometRi3D.UseAbsoluteTolerance = mode;\n            GeometRi3D.Tolerance = tol;\n        }\n\n        [TestMethod()]\n        public void TriangleIntersectionWithSegmentRelativeTest()\n        {\n\n            double tol = GeometRi3D.Tolerance;\n            bool mode = GeometRi3D.UseAbsoluteTolerance;\n            GeometRi3D.Tolerance = 0.01;\n            GeometRi3D.UseAbsoluteTolerance = false;\n\n            Point3d p1 = new Point3d(0, 0, 0);\n            Point3d p2 = new Point3d(6, 0, 0);\n            Point3d p3 = new Point3d(0, 6, 0);\n\n            Triangle t = new Triangle(p1, p2, p3);\n\n            Segment3d s = new Segment3d(new Point3d(0, 0, 0.01), new Point3d(3.01, 3, 0));\n            Assert.IsTrue((Segment3d)t.IntersectionWith(s) == s);\n\n            s = new Segment3d(new Point3d(2, 2, 0.01), new Point3d(5.01, 5, 0));\n            Assert.IsTrue((Segment3d)t.IntersectionWith(s) == new Segment3d(new Point3d(2, 2, 0), new Point3d(3, 3, 0)));\n\n            // Resore initial state\n            GeometRi3D.UseAbsoluteTolerance = mode;\n            GeometRi3D.Tolerance = tol;\n        }\n\n        [TestMethod()]\n        public void TriangleIntersectionWithRayTest()\n        {\n\n            Point3d p1 = new Point3d(0, 0, 0);\n            Point3d p2 = new Point3d(6, 0, 0);\n            Point3d p3 = new Point3d(0, 6, 0);\n\n            Triangle t = new Triangle(p1, p2, p3);\n\n            Ray3d r = new Ray3d(new Point3d(1, 1, 0), new Vector3d(1, 1, 0));\n            Assert.IsTrue((Segment3d)t.IntersectionWith(r) == new Segment3d(new Point3d(1, 1, 0), new Point3d(3, 3, 0)));\n\n            t = new Triangle(p1, p3, p2);\n            r = new Ray3d(new Point3d(1, 1, 0), new Vector3d(1, 1, 0));\n            Assert.IsTrue((Segment3d)t.IntersectionWith(r) == new Segment3d(new Point3d(1, 1, 0), new Point3d(3, 3, 0)));\n\n            r = new Ray3d(new Point3d(0, 0, 10), new Vector3d(0, 0, -1));\n            Assert.IsTrue((Point3d)t.IntersectionWith(r) == new Point3d(0, 0, 0));\n\n            r = new Ray3d(new Point3d(0, 0, -10), new Vector3d(0, 0, 1));\n            Assert.IsTrue((Point3d)t.IntersectionWith(r) == new Point3d(0, 0, 0));\n\n            r = new Ray3d(new Point3d(4, 4, -10), new Vector3d(0, 0, 1));\n            Assert.IsNull(t.IntersectionWith(r));\n\n        }\n\n        [TestMethod()]\n        public void PointInTriangleTest2()\n        {\n\n            Point3d p1 = new Point3d(0, 0, 0);\n            Point3d p2 = new Point3d(6, 0, 0);\n            Point3d p3 = new Point3d(0, 6, 0);\n\n            Triangle t = new Triangle(p1, p2, p3);\n            Point3d p = new Point3d(4, 4, 0);\n            Assert.IsFalse(p.BelongsTo(t));\n\n            p = new Point3d(6, 0.5, 0);\n            Assert.IsFalse(p.BelongsTo(t));\n\n            p = new Point3d(5, -0.5, 0);\n            Assert.IsFalse(p.BelongsTo(t));\n\n            p = new Point3d(2, 5, 0);\n            Assert.IsFalse(p.BelongsTo(t));\n\n            p = new Point3d(2, 2, 0.1);\n            Assert.IsFalse(p.BelongsTo(t));\n\n            p = new Point3d(2, 2, 0);\n            Assert.IsTrue(p.BelongsTo(t));\n\n            p = new Point3d(5, 1, 0);\n            Assert.IsTrue(p.BelongsTo(t));\n\n            p = new Point3d(0, 1, 0);\n            Assert.IsTrue(p.BelongsTo(t));\n\n            p = new Point3d(2, 0, 0);\n            Assert.IsTrue(p.BelongsTo(t));\n\n        }\n\n        [TestMethod()]\n        public void TriangleDistanceToCircleTest()\n        {\n            Point3d p1 = new Point3d(-0.5, -0.5, -0.5);\n            Point3d p2 = new Point3d(0.5, 0.5, -0.5);\n            Point3d p3 = new Point3d(0.5, -0.5, -0.5);\n            Triangle t = new Triangle(p1, p2, p3);\n\n            Circle3d c = new Circle3d(new Point3d(-1.3195, -1.0435, -0.70047), 0.35, new Vector3d(0.83694, -0.13208, -0.53112));\n\n            double dist = t.DistanceTo(c);\n            Assert.IsTrue(dist > 0);\n\n        }\n\n        [TestMethod()]\n        public void TriangleIntersectsCircleTest()\n        {\n\n            Circle3d c = new Circle3d(new Point3d(), 1.0, new Vector3d(0, 0, 1));\n\n            // Coplanar objects\n            // Triangle's vertecx inside circle\n            Point3d p1 = new Point3d(0.5, 0.5, 0);\n            Point3d p2 = new Point3d(2, 3, 0);\n            Point3d p3 = new Point3d(-3, 1, 0);\n            Triangle t = new Triangle(p1, p2, p3);\n            Assert.IsTrue(c.Intersects(t));\n\n            // circle's center inside triangle\n            p1 = new Point3d(-5, -5, 0);\n            p2 = new Point3d(5, -5, 0);\n            p3 = new Point3d(0, 5, 0);\n            t = new Triangle(p1, p2, p3);\n            Assert.IsTrue(c.Intersects(t));\n\n            // circle touch triangle\n            p1 = new Point3d(1, -1, 0);\n            p2 = new Point3d(1, 1, 0);\n            p3 = new Point3d(3, 0, 0);\n            t = new Triangle(p1, p2, p3);\n            Assert.IsTrue(c.Intersects(t));\n\n            // Non-intersecting objects\n            p1 = new Point3d(1.5, -1, 0);\n            p2 = new Point3d(1.5, 1, 0);\n            p3 = new Point3d(3, 0, 0);\n            t = new Triangle(p1, p2, p3);\n            Assert.IsFalse(c.Intersects(t));\n\n            // Non-coplanar objects\n            p1 = new Point3d(0.5, 0.5, -1);\n            p2 = new Point3d(0.5, -0.5, 1);\n            p3 = new Point3d(0, 0, 1);\n            t = new Triangle(p1, p2, p3);\n            Assert.IsTrue(c.Intersects(t));\n\n            // Non-intersecting objects\n            p1 = new Point3d(1.5, -1, -1);\n            p2 = new Point3d(1.5, 1, -2);\n            p3 = new Point3d(3, 0, -1);\n            t = new Triangle(p1, p2, p3);\n            Assert.IsFalse(c.Intersects(t));\n\n            // Non-intersecting objects\n            p1 = new Point3d(1, 1, -1);\n            p2 = new Point3d(1, 1, -2);\n            p3 = new Point3d(1, 5, -1);\n            t = new Triangle(p1, p2, p3);\n            Assert.IsFalse(c.Intersects(t));\n        }\n\n\n        [TestMethod()]\n        public void TriangleIntersectsTriangleTest()\n        {\n            Triangle t1 = new Triangle(new Point3d(0, 0, 0), new Point3d(10, 0, 0), new Point3d(0, 10, 0));\n\n            // Coplanar objects\n            // Triangle 2 is inside triangle 1\n            Triangle t2 = new Triangle(new Point3d(1, 1, 0), new Point3d(2, 1, 0), new Point3d(1, 2, 0));\n            Assert.IsTrue(t2.Intersects(t1));\n            Assert.IsTrue(t1.Intersects(t2));\n\n            // Triangle 1 is inside triangle 2\n            t2 = new Triangle(new Point3d(-1, -1, 0), new Point3d(20, -1, 0), new Point3d(-1, 20, 0));\n            Assert.IsTrue(t2.Intersects(t1));\n            Assert.IsTrue(t1.Intersects(t2));\n\n            // Triangle 2 touch vertex of triangle 1\n            t2 = new Triangle(new Point3d(10, 0, 0), new Point3d(20, 0, 0), new Point3d(10, -10, 0));\n            Assert.IsTrue(t2.Intersects(t1));\n            Assert.IsTrue(t1.Intersects(t2));\n\n            // Triangle 2 touch edge of triangle 1\n            t2 = new Triangle(new Point3d(5, 0, 0), new Point3d(10, -5, 0), new Point3d(0, -5, 0));\n            Assert.IsTrue(t2.Intersects(t1));\n            Assert.IsTrue(t1.Intersects(t2));\n\n            // Triangle 2 intersects triangle 1\n            t2 = new Triangle(new Point3d(5, -1, 0), new Point3d(5, 20, 0), new Point3d(6, -1, 0));\n            Assert.IsTrue(t2.Intersects(t1));\n            Assert.IsTrue(t1.Intersects(t2));\n\n            // Non-intersecting objects\n            t2 = new Triangle(new Point3d(-5, -1, 0), new Point3d(-5, -20, 0), new Point3d(-6, -1, 0));\n            Assert.IsFalse(t2.Intersects(t1));\n            Assert.IsFalse(t1.Intersects(t2));\n\n\n            // Non-coplanar objects\n            t2 = new Triangle(new Point3d(5, 1, 1), new Point3d(6, 1, -1), new Point3d(5, 2, 1));\n            Assert.IsTrue(t2.Intersects(t1));\n            Assert.IsTrue(t1.Intersects(t2));\n\n            t2 = new Triangle(new Point3d(5, 1, 1), new Point3d(6, 1, 0), new Point3d(5, 2, 1));\n            Assert.IsTrue(t2.Intersects(t1));\n            Assert.IsTrue(t1.Intersects(t2));\n\n            // Non-intersecting objects\n            t2 = new Triangle(new Point3d(15, 1, 0), new Point3d(15, -20, -1), new Point3d(15, -1, 5));\n            Assert.IsFalse(t2.Intersects(t1));\n            Assert.IsFalse(t1.Intersects(t2));\n\n        }\n\n        [TestMethod()]\n        public void TriangleClosestPointTest()\n        {\n            Point3d p1 = new Point3d(0, 0, 0);\n            Point3d p2 = new Point3d(10, 0, 0);\n            Point3d p3 = new Point3d(5, 5, 0);\n            Triangle t = new Triangle(p1, p2, p3);\n\n            Point3d p = new Point3d(1, 1, 1);\n            Assert.AreEqual(p.ClosestPoint(t), new Point3d(1, 1, 0));\n\n            p = new Point3d(-3, -1, 0);\n            Assert.AreEqual(p.ClosestPoint(t), new Point3d(0, 0, 0));\n        }\n\n        [TestMethod()]\n        public void TriangleDistanceToPointTest_01()\n        {\n            Point3d p1 = new Point3d(0, 0, 0);\n            Point3d p2 = new Point3d(2, 0, 0);\n            Point3d p3 = new Point3d(0, 2, 0);\n            Triangle t = new Triangle(p1, p2, p3);\n\n            Point3d p = new Point3d(1, 1, 8);\n            Assert.IsTrue(Abs(t.DistanceTo(p) - 8) < GeometRi3D.Tolerance);\n            Assert.IsTrue(Abs(t.DistanceSquared(p) - 64) < GeometRi3D.Tolerance);\n\n            p = new Point3d(5, 0, 4);\n            Assert.IsTrue(Abs(t.DistanceTo(p) - 5) < GeometRi3D.Tolerance);\n            Assert.IsTrue(Abs(t.DistanceSquared(p) - 25) < GeometRi3D.Tolerance);\n\n\n        }\n\n        [TestMethod()]\n        public void TriangleDistanceToPointTest_02()\n        {\n            Point3d p1 = new Point3d(2, 0, 0);\n            Point3d p2 = new Point3d(2, 1, 0);\n            Point3d p3 = new Point3d(2, 0, 1);\n            Triangle t = new Triangle(p1, p2, p3);\n\n            Point3d p = new Point3d(0, 0, 0);\n            Assert.IsTrue(Abs(t.DistanceTo(p) - 2) < GeometRi3D.Tolerance);\n            Assert.IsTrue(Abs(t.DistanceSquared(p) - 4) < GeometRi3D.Tolerance);\n\n        }\n\n        [TestMethod()]\n        public void TriangleDistanceToSegmentTest_01()\n        {\n            Point3d p1 = new Point3d(0, 0, 0);\n            Point3d p2 = new Point3d(2, 0, 0);\n            Point3d p3 = new Point3d(0, 2, 0);\n            Triangle t = new Triangle(p1, p2, p3);\n\n            // One point belongs to triangle\n            Segment3d s = new Segment3d(new Point3d(0, 0, 0), new Point3d(-1, -1, -1));\n            double dist = t.DistanceTo(s, out Point3d point_on_triangle, out Point3d point_on_segment);\n            Assert.IsTrue(Abs(dist - 0) < GeometRi3D.Tolerance);\n            Assert.IsTrue(point_on_triangle == t.A);\n            Assert.IsTrue(point_on_segment == s.P1);\n        }\n\n        [TestMethod()]\n        public void TriangleDistanceToSegmentTest_02()\n        {\n            Point3d p1 = new Point3d(0, 0, 0);\n            Point3d p2 = new Point3d(2, 0, 0);\n            Point3d p3 = new Point3d(0, 2, 0);\n            Triangle t = new Triangle(p1, p2, p3);\n\n            // Segment is coplanar and belongs to triangle\n            Segment3d s = new Segment3d(new Point3d(0.5, 0.5, 0), new Point3d(1, 1, 0));\n            double dist = t.DistanceTo(s, out Point3d point_on_triangle, out Point3d point_on_segment);\n            Assert.IsTrue(Abs(dist - 0) < GeometRi3D.Tolerance);\n            Assert.IsTrue(point_on_triangle == new Point3d(0.5, 0.5, 0));\n            Assert.IsTrue(point_on_segment == s.P1);\n        }\n\n        [TestMethod()]\n        public void TriangleDistanceToSegmentTest_03()\n        {\n            Point3d p1 = new Point3d(0, 0, 0);\n            Point3d p2 = new Point3d(2, 0, 0);\n            Point3d p3 = new Point3d(0, 2, 0);\n            Triangle t = new Triangle(p1, p2, p3);\n\n            // Segment is coplanar and does not belong to triangle\n            Segment3d s = new Segment3d(new Point3d(3, 0, 0), new Point3d(3, 5, 0));\n            double dist = t.DistanceTo(s, out Point3d point_on_triangle, out Point3d point_on_segment);\n            Assert.IsTrue(Abs(dist - 1) < GeometRi3D.Tolerance);\n            Assert.IsTrue(point_on_triangle == new Point3d(2, 0, 0));\n            Assert.IsTrue(point_on_segment == s.P1);\n        }\n\n        [TestMethod()]\n        public void TriangleDistanceToSegmentTest_04()\n        {\n            Point3d p1 = new Point3d(0, 0, 0);\n            Point3d p2 = new Point3d(2, 0, 0);\n            Point3d p3 = new Point3d(0, 2, 0);\n            Triangle t = new Triangle(p1, p2, p3);\n\n            // Segment intersects triangle\n            Segment3d s = new Segment3d(new Point3d(0, 0, -1), new Point3d(2, 2, 1));\n            double dist = t.DistanceTo(s, out Point3d point_on_triangle, out Point3d point_on_segment);\n            Assert.IsTrue(Abs(dist - 0) < GeometRi3D.Tolerance);\n            Assert.IsTrue(point_on_triangle == new Point3d(1, 1, 0));\n            Assert.IsTrue(point_on_segment == new Point3d(1, 1, 0));\n        }\n\n        [TestMethod()]\n        public void TriangleDistanceToSegmentTest_05()\n        {\n            Point3d p1 = new Point3d(0, 0, 0);\n            Point3d p2 = new Point3d(2, 0, 0);\n            Point3d p3 = new Point3d(0, 2, 0);\n            Triangle t = new Triangle(p1, p2, p3);\n\n            // Projection point belongs to triangle and is closest\n            Segment3d s = new Segment3d(new Point3d(0.5, 0.5, 1), new Point3d(5, 5, 10));\n            double dist = t.DistanceTo(s, out Point3d point_on_triangle, out Point3d point_on_segment);\n            Assert.IsTrue(Abs(dist - 1) < GeometRi3D.Tolerance);\n            Assert.IsTrue(point_on_triangle == new Point3d(0.5, 0.5, 0));\n            Assert.IsTrue(point_on_segment == s.P1);\n        }\n\n        [TestMethod()]\n        public void TriangleDistanceToSegmentTest_06()\n        {\n            Point3d p1 = new Point3d(0, 0, 0);\n            Point3d p2 = new Point3d(2, 0, 0);\n            Point3d p3 = new Point3d(0, 2, 0);\n            Triangle t = new Triangle(p1, p2, p3);\n\n            // General case\n            Segment3d s = new Segment3d(new Point3d(0, -1, -1), new Point3d(2, -1, 1));\n            double dist = t.DistanceTo(s, out Point3d point_on_triangle, out Point3d point_on_segment);\n            Assert.IsTrue(Abs(dist - 1) < GeometRi3D.Tolerance);\n            Assert.IsTrue(point_on_triangle == new Point3d(1, 0, 0));\n            Assert.IsTrue(point_on_segment == new Point3d(1, -1, 0));\n        }\n\n        [TestMethod()]\n        public void TriangleIntersectsSphereTest_01()\n        {\n            Point3d p1 = new Point3d(0, 0, 0);\n            Point3d p2 = new Point3d(2, 0, 0);\n            Point3d p3 = new Point3d(0, 2, 0);\n            Triangle t = new Triangle(p1, p2, p3);\n\n            Sphere s = new Sphere(new Point3d(0.5, 0.5, 1.1), 1);\n            Assert.IsFalse(t.Intersects(s));\n\n            s = new Sphere(new Point3d(2, 2, 0.5), 1);\n            Assert.IsFalse(t.Intersects(s));\n\n            s = new Sphere(new Point3d(0.5, 0.5, 0.9), 1);\n            Assert.IsTrue(t.Intersects(s));\n\n            s = new Sphere(new Point3d(1.1, 1.1, 0.7), 1);\n            Assert.IsTrue(t.Intersects(s));\n\n\n        }\n\n        [TestMethod()]\n        public void TriangleDistanceToTriangleTest_01()\n        {\n            Point3d p1 = new Point3d(0, 0, 0);\n            Point3d p2 = new Point3d(2, 0, 0);\n            Point3d p3 = new Point3d(0, 2, 0);\n            Triangle t1 = new Triangle(p1, p2, p3);\n\n            p1 = new Point3d(3, 0, 0);\n            p2 = new Point3d(5, 0, 0);\n            p3 = new Point3d(4, 2, 0);\n            Triangle t2 = new Triangle(p1, p2, p3);\n\n            double dist = t1.DistanceTo(t2, out Point3d point_on_triangle1, out Point3d point_on_triangle2);\n            Assert.IsTrue(Abs(dist - 1) < GeometRi3D.Tolerance);\n            Assert.IsTrue(point_on_triangle1 == new Point3d(2, 0, 0));\n            Assert.IsTrue(point_on_triangle2 == new Point3d(3, 0, 0));\n        }\n\n        [TestMethod()]\n        public void TriangleDistanceToTriangleTest_02()\n        {\n            Point3d p1 = new Point3d(0, 0, 0);\n            Point3d p2 = new Point3d(2, 0, 0);\n            Point3d p3 = new Point3d(0, 2, 0);\n            Triangle t1 = new Triangle(p1, p2, p3);\n\n            p1 = new Point3d(1, 1, 1);\n            p2 = new Point3d(3, 2, 3);\n            p3 = new Point3d(4, 2, 5);\n            Triangle t2 = new Triangle(p1, p2, p3);\n\n            double dist = t1.DistanceTo(t2, out Point3d point_on_triangle1, out Point3d point_on_triangle2);\n            Assert.IsTrue(Abs(dist - 1) < GeometRi3D.Tolerance);\n            Assert.IsTrue(point_on_triangle1 == new Point3d(1, 1, 0));\n            Assert.IsTrue(point_on_triangle2 == new Point3d(1, 1, 1));\n        }\n\n        [TestMethod()]\n        public void PointDistanceToTriangleTest()\n        {\n            Triangle triangle = new Triangle(\n                new Point3d(0, 0, 0),\n                new Point3d(10000, 0, 0),\n                new Point3d(0, 10000, 0));\n\n            Point3d point = new Point3d(3286.59, 5000, 0);\n\n            double distance = triangle.DistanceTo(point);\n\n            Assert.AreEqual(distance, 0);\n            Assert.AreEqual(triangle.DistanceSquared(point), 0);\n        }\n\n        [TestMethod()]\n        public void PointDistanceToTriangleTest_02()\n        {\n            Triangle triangle = new Triangle(\n                new Point3d(0, 0, 0),\n                new Point3d(10, 0, 0),\n                new Point3d(0, 10, 0));\n\n            Point3d point = new Point3d(5, 5, 0);\n\n            double distance = triangle.DistanceTo(point);\n\n            Assert.AreEqual(distance, 0);\n            Assert.AreEqual(triangle.DistanceSquared(point), 0);\n        }\n\n        [TestMethod()]\n        public void TriangleRayIntersectionTest()\n        {\n            Point3d A = new Point3d(2000, 240, -30);\n            Point3d B = new Point3d(2000, 280, -30);\n            Point3d C = new Point3d(2000, 240, 30);\n\n            // Coord3d coord = new Coord3d(new Point3d(1000, 280, 0), new Vector3d(1, 0, 0), new Vector3d(0, 1, 0));\n            // Segment3d seg = new Segment3d(\n            //     new Point3d(1000, 0, 0, coord),\n            //     new Point3d(1000, 1000, 0, coord));\n            //\n            // Rotation r = new Rotation(Coord3d.GlobalCS.Zaxis, 67 * Math.PI / 180);\n            // coord.Rotate(Coord3d.GlobalCS.Zaxis, 67 * Math.PI / 180);\n            // //seg = seg.Rotate(r, seg.P1);\n            //\n            //      //   coord.Rotate(coord.Zaxis, - 67 * Math.PI / 180);\n            //\n            // Line3d ltemp = new Line3d(new Point3d(2000, 260, 0), new Vector3d(1, 0, 0));\n            // Point3d pt = seg.IntersectionWith(ltemp) as Point3d;\n            // Ray3d ray = new Ray3d(pt, new Vector3d(1, 0, 0));\n            // Triangle t = new Triangle(A, B, C);\n            //\n            // Assert.IsTrue(t.IntersectionWith(ray).Equals(new Point3d(2000, 260, 0)));\n\n            //            Segment3d seg1 = new Segment3d(\n            //new Point3d(760.73, 716.34, 0)\n            //, new Point3d(726.03, 742.49, 0));\n            //\n            //            Segment3d seg2 = new Segment3d(\n            //new Point3d(726.03, 742.49, 0)\n            //, new Point3d(813.88, 676.29, 0));\n\n            Segment3d seg1 = new Segment3d(\nnew Point3d(10, 10, 0)\n, new Point3d(20, 20, 0));\n\n            Segment3d seg2 = new Segment3d(\nnew Point3d(15, 15, 0)\n, new Point3d(25, 25, 0));\n\n            var inter = (Segment3d)seg1.IntersectionWith(seg2);\n\n            inter.P1 = inter.P1.ConvertToGlobal();\n            ;\n\n        }\n\n        [TestMethod()]\n        public void TriangleSegmentIntersectMiddleOfAB_BC()\n        {\n            var lineSegment = new Segment3d(new Point3d(0.75, 0.25, 0), new Point3d(0, 1, 0));\n            var triangle = new Triangle(\n                new Point3d(0, 0, 0),\n                new Point3d(1, 0, 0),\n                new Point3d(1, 1, 0));\n\n            var intersectionWith = triangle.IntersectionWith(lineSegment);\n            Assert.IsTrue(intersectionWith is Segment3d);\n\n            var intersection = intersectionWith as Segment3d;\n            Segment3d s = new Segment3d(new Point3d(0.5, 0.5, 0), new Point3d(0.75, 0.25, 0));\n            Assert.IsTrue(intersection.Equals(s));\n        }\n\n\n    }\n}\n\n"
  },
  {
    "path": "GeometRi.Tests/Vector3dTest.cs",
    "content": "﻿using System;\nusing static System.Math;\nusing Microsoft.VisualStudio.TestTools.UnitTesting;\nusing GeometRi;\n\nnamespace GeometRi_Tests\n{\n    [TestClass]\n    public class Vector3dTest\n    {\n        //===============================================================\n        // Vector3d tests\n        //===============================================================\n\n        [TestMethod()]\n        public void VectorAngleTest()\n        {\n            // Angle < 90 \n            Vector3d v1 = new Vector3d(1, 0, 0);\n            Vector3d v2 = new Vector3d(1, 1, 0);\n            Assert.IsTrue(Abs(v1.AngleToDeg(v2) - 45) < GeometRi3D.Tolerance);\n        }\n\n        [TestMethod()]\n        public void VectorAngleTest2()\n        {\n            // Angle > 90 \n            Vector3d v1 = new Vector3d(1, 0, 0);\n            Vector3d v2 = new Vector3d(-1, 1, 0);\n            Assert.IsTrue(Abs(v1.AngleToDeg(v2) - 135) < GeometRi3D.Tolerance);\n        }\n\n        [TestMethod()]\n        public void VectorAngleToPlaneTest()\n        {\n            Plane3d s = new Plane3d();\n            // XY plane\n\n            Vector3d v = new Vector3d(1, 0, 0);\n            Assert.IsTrue(Abs(v.AngleTo(s)) < GeometRi3D.Tolerance);\n            Assert.IsTrue(Abs(s.AngleTo(v)) < GeometRi3D.Tolerance);\n\n            v = new Vector3d(0, 0, 1);\n            Assert.IsTrue(Abs(v.AngleTo(s) - PI / 2) < GeometRi3D.Tolerance);\n            Assert.IsTrue(Abs(s.AngleTo(v) - PI / 2) < GeometRi3D.Tolerance);\n\n            v = new Vector3d(0, 0, -1);\n            Assert.IsTrue(Abs(v.AngleTo(s) - PI / 2) < GeometRi3D.Tolerance);\n            Assert.IsTrue(Abs(s.AngleTo(v) - PI / 2) < GeometRi3D.Tolerance);\n\n            v = new Vector3d(1, 0, 1);\n            Assert.IsTrue(Abs(v.AngleTo(s) - PI / 4) < GeometRi3D.Tolerance);\n            Assert.IsTrue(Abs(s.AngleTo(v) - PI / 4) < GeometRi3D.Tolerance);\n\n            v = new Vector3d(1, 0, -1);\n            Assert.IsTrue(Abs(v.AngleTo(s) - PI / 4) < GeometRi3D.Tolerance);\n            Assert.IsTrue(Abs(s.AngleTo(v) - PI / 4) < GeometRi3D.Tolerance);\n\n        }\n    }\n}\n"
  },
  {
    "path": "GeometRi.Tests/packages.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<packages>\n  <package id=\"MSTest.TestAdapter\" version=\"1.1.11\" targetFramework=\"net45\" />\n  <package id=\"MSTest.TestFramework\" version=\"1.1.11\" targetFramework=\"net45\" />\n</packages>"
  },
  {
    "path": "GeometRi.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio 15\nVisualStudioVersion = 15.0.26430.14\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"GeometRi\", \"GeometRi\\GeometRi.csproj\", \"{F73E450B-8F34-4B6B-8BF3-B7A17D9F52C5}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"GeometRi.Example\", \"GeometRi.Example\\GeometRi.Example.csproj\", \"{3D086E96-C1D2-42DB-9EED-300C3A9BBAA8}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"GeometRi.Tests\", \"GeometRi.Tests\\GeometRi.Tests.csproj\", \"{B99F3733-D205-4EDA-9B4C-F2F68A9DFD59}\"\nEndProject\nProject(\"{F2A71F9B-5D33-465A-A702-920D77279786}\") = \"GeometRi.Example.FSharp\", \"GeometRi.Example.FSharp\\GeometRi.Example.FSharp.fsproj\", \"{D59A9E53-D080-4AE9-B5CB-E60F2BF5E634}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"GeometRi.Benchmarks\", \"GeometRi.Benchmarks\\GeometRi.Benchmarks.csproj\", \"{BBB4B097-55D3-4135-AF02-471E007E3FDB}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{F73E450B-8F34-4B6B-8BF3-B7A17D9F52C5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{F73E450B-8F34-4B6B-8BF3-B7A17D9F52C5}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{F73E450B-8F34-4B6B-8BF3-B7A17D9F52C5}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{F73E450B-8F34-4B6B-8BF3-B7A17D9F52C5}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{3D086E96-C1D2-42DB-9EED-300C3A9BBAA8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{3D086E96-C1D2-42DB-9EED-300C3A9BBAA8}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{3D086E96-C1D2-42DB-9EED-300C3A9BBAA8}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{3D086E96-C1D2-42DB-9EED-300C3A9BBAA8}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{B99F3733-D205-4EDA-9B4C-F2F68A9DFD59}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{B99F3733-D205-4EDA-9B4C-F2F68A9DFD59}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{B99F3733-D205-4EDA-9B4C-F2F68A9DFD59}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{B99F3733-D205-4EDA-9B4C-F2F68A9DFD59}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{D59A9E53-D080-4AE9-B5CB-E60F2BF5E634}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{D59A9E53-D080-4AE9-B5CB-E60F2BF5E634}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{D59A9E53-D080-4AE9-B5CB-E60F2BF5E634}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{D59A9E53-D080-4AE9-B5CB-E60F2BF5E634}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{BBB4B097-55D3-4135-AF02-471E007E3FDB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{BBB4B097-55D3-4135-AF02-471E007E3FDB}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{BBB4B097-55D3-4135-AF02-471E007E3FDB}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{BBB4B097-55D3-4135-AF02-471E007E3FDB}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {F1B4727F-687A-461B-81A0-20DD7CA681A2}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "LICENSE.txt",
    "content": "MIT License\n\nCopyright (c) 2017-2025 Sergey Tarasov\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# GeometRi\n### Simple and lightweight computational geometry library for .Net\n\nMain purpose of the GeometRi library is manipulations with basic\ngeometrical primitives, such as point, line, plane, sphere, triangle in 3D space:\ntranslation and rotation operations, distance calculation, intersections,\northogonal projections of one object into another, etc. The objects can be defined\nin global or in one of the local coordinate systems and converted form one coordinate\nsystem into another.\n\nThe library was build to be as simple and intuitive as posible. Users do not have to remember the reference coordinate\nsystem of each object. The objects store the coordinate system they are defined in and all transformations\nwill be caried out implicitly when necessary.  \n\nThe main goal was simplisity and readability of the code, therefore speed and robustness was not a priority.\nGlobal tolerance property is used for proximity checking, not an exact robust algorithms.\n\n## [Release notes](./ReleaseNotes.md)\n\n* [Installation](https://github.com/RiSearcher/GeometRi.CSharp#installation)\n* [Examples](https://github.com/RiSearcher/GeometRi.CSharp#examples)\n* [Classes](https://github.com/RiSearcher/GeometRi.CSharp#classes)\n    * [Point3d](https://github.com/RiSearcher/GeometRi.CSharp#point3d)\n    * [Vector3d](https://github.com/RiSearcher/GeometRi.CSharp#vector3d)\n    * [Line3d](https://github.com/RiSearcher/GeometRi.CSharp#line3d)\n    * [Ray3d](https://github.com/RiSearcher/GeometRi.CSharp#ray3d)\n    * [Segment3d](https://github.com/RiSearcher/GeometRi.CSharp#segment3d)\n    * [Plane3d](https://github.com/RiSearcher/GeometRi.CSharp#plane3d)\n    * [Sphere](https://github.com/RiSearcher/GeometRi.CSharp#sphere)\n    * [Circle3d](https://github.com/RiSearcher/GeometRi.CSharp#circle3d)\n    * [Ellipse](https://github.com/RiSearcher/GeometRi.CSharp#ellipse)\n    * [Ellipsoid](https://github.com/RiSearcher/GeometRi.CSharp#ellipsoid)\n    * [Box3d](https://github.com/RiSearcher/GeometRi.CSharp#box3d)\n    * [Triangle](https://github.com/RiSearcher/GeometRi.CSharp#triangle)\n    * [Tetrahedron](https://github.com/RiSearcher/GeometRi.CSharp#tetrahedron)\n    * [ConvexPolyhedron](https://github.com/RiSearcher/GeometRi.CSharp#convexpolyhedron)\n    * [Coord3d](https://github.com/RiSearcher/GeometRi.CSharp#coord3d)\n    * [Matrix3d](https://github.com/RiSearcher/GeometRi.CSharp#matrix3d)\n    * [Quaternion](https://github.com/RiSearcher/GeometRi.CSharp#quaternion)\n    * [Rotation](https://github.com/RiSearcher/GeometRi.CSharp#rotation)\n    * [GeometRi3D](https://github.com/RiSearcher/GeometRi.CSharp#geometri3d)\n\n## Installation\nUse NuGet to install library. Search for __GeometRi__ in NuGet package manager or type in the Package Manager Console:\n```\nInstall-Package GeometRi\n```\n\n## Examples\n\n* Ptolemy's construction of a pentagon inside the circle: [C#](https://dotnetfiddle.net/0Is1ZV)\n* Mascheroni construction of a regular pentagon: [C#](https://dotnetfiddle.net/45iLTa)\n* Rytz's construction: [C#](https://dotnetfiddle.net/WqeS69), [VB.Net](https://dotnetfiddle.net/2c04c0)\n\n## Classes\n\n* __Point3d__ and __Vector3d__ are two base classes, representing points and vectors in 3D space.\nObjects of type Point3d or Vector3d can be defined in global or in local coordinate systems.\n\n* __Line3d__, __Ray3d__, __Segment3d__, __Plane3d__, __Circle3d__, __Sphere__, __Ellipse__, __Ellipsoid__, __Box3d__, __Triangle__, __AABB__, __Tetrahedron__, and __ConvexPolyhedron__\nare compound classes, which are defined in terms of points and vectors.\n\n* __Coord3d__, __Rotation__, __Quaternion__ and __Matrix3d__ are auxiliary classes.\n\n* __GeometRi3d__ is an abstract class, which defines some common functionality, for example global tolerance property (GeometRi3d.Tolerance)\nused in proximity operations by other classes. Implements tolerance based equality methods: AlmostEqual(double, double), NotEqual(double,double),\nGreater(double, double) and Smaller(double, double).\n\n## Point3d\n\nOne of the base classes, can be constructed by three double numbers (X, Y and Z) or from double array.\nEach constructor has optional parameter 'coord' for local coordinate system in which point will be defined.\nBy default all points are defined in global coordinate system.\n### Properties\n* __X__ - X coordinate in reference coordinate system\n* __Y__ - Y coordinate in reference coordinate system\n* __Z__ - Z coordinate in reference coordinate system\n* __Coord__ - reference coordinate system\n* __ToVector__ - radius vector of point\n### Methods\n* __Copy__ - Creates copy of the object\n* __ConvertTo__ - convert point to local coordinate system\n* __ConvertToGlobal__ - convert point to global coordinate system\n* __Add__ - add two points\n* __Subtract__ - subtract one point from other\n* __Scale__ - scale point by given number\n* __DistanceTo__ - shortest distance from point to point to other objects\n* __ClosestPoint__ - closest point on circle, box, triangle, sphere, ellipse, ellipsoid, tetrahedron\n* __ProjectionTo__ - orthogonal projection of point to line, plane or sphere\n* __BelongsTo__ - test if point is located in the epsilon neighborhood of the object\n* __IsInside__ - test if point is located strictly inside (not in the epsilon neighborhood of the boundary) of the object\n* __IsOutside__ - test if point is located outside of the epsilon neighborhood of the object\n* __IsOnBoundary__ - test if point is located in the epsilon neighborhood of the object's boundary\n* __Translate__ - translate point by vector\n* __Rotate__ - rotate point around origin or other point\n* __Reflect__ - reflect point in point, line or plane\n* __Equals__ - check if two points are equals\n* __ToString__ - string representation of point in global or local coordinate system\n### Static methods\n* __CollinearPoints__ - check if three points are collinear\n### Overloaded operators\n* __+__ - add two points\n* __-__ - subtract one point from other\n* __-__ - unary operator\n* __*__ - scale point by number\n* __/__ - scale point by number\n* __=__ - equality check\n* __<>__ - unequality check\n\n## Vector3d\n\nSecond base class, representing vector in 3D space. Constructed by three components (X, Y and Z) or from double array\n(with optional 'coord' parameter for local cordinate system). Additionally, can be constructed by point,\nrepresenting radius vector of that point, or by two points, representing vector from first point to another. In this cases\nthe vector will be defined in the same coordinate system as the first operand.\n### Properties\n* __X__ - X component in reference coordinate system\n* __Y__ - Y component in reference coordinate system\n* __Z__ - Z component in reference coordinate system\n* __Coord__ - reference coordinate system\n* __Norm__ - Norm of a vector\n* __ToPoint__ - point, represented by vector starting in origin\n* __OrthogonalVector__ - return arbitrary vector, orthogonal to the current vector\n### Methods\n* __Copy__ - Creates copy of the object\n* __ConvertTo__ - convert vector to local coordinate system\n* __ConvertToGlobal__ - convert vector to global coordinate system\n* __Normalize__ - normalize the current vector\n* __Normalized__ - return normalized vector\n* __IsParallelTo__ - check if two objects are parallel\n* __IsNotParallelTo__ - check if two objects are NOT parallel\n* __IsOrthogonalTo__ - check if two objects are orthogonal\n* __AngleTo__ - angle between two objects\n* __AngleToDeg__ - angle between two objects (in degrees)\n* __Add__ - overloaded, add number or vector\n* __Subtract__ - oveloaded, subtract number or vector\n* __Mult__ - overloaded, multiply by number or vector\n* __Dot__ - dot product of two vectors\n* __ProjectionTo__ - return projection of the current vector to the second vector\n* __Rotate__ - rotate vector around origin\n* __Reflect__ - reflect vector in point, line or plane\n* __Equals__ - check if two vectors are equals\n* __ToString__ - string representation of vector in global or local coordinate system\n\n## Line3d \n\nInfinite line  in 3D space and defined by any point lying on the line and a direction vector.\n### Properties\n* __Point__ - base point of the line\n* __Direction__ - direction vector of the line\n### Methods\n* __Copy__ - Creates copy of the object\n* __DistanceTo__ - shortest distance to point, line, ray or segment\n* __PerpendicularTo__ - point on the perpendicular to the second line\n* __IntersectionWith__ - intersection of line with plane, ellipsoid, ellipse, circle, triangle, segment or sphere\n* __ProjectionTo__ - orthogonal projection of a line to the plane\n* __IsParallelTo__ - check if two objects are parallel\n* __IsNotParallelTo__ - check if two objects are NOT parallel\n* __IsOrthogonalTo__ - check if two objects are orthogonal\n* __IsCoplanarTo__ - check if line is coplanar to other linear or planar object\n* __AngleTo__ - angle between two objects\n* __AngleToDeg__ - angle between two objects (in degrees)\n* __Translate__ - translate line by vector\n* __Rotate__ - rotate line around origin or other point\n* __Reflect__ - reflect line in point, line or plane\n* __Equals__ - check if two lines are equals\n* __ToString__ - string representation of line in global or local coordinate system\n\n## Ray3d\n\nRepresent ray in 3D space and is defined by starting point and direction vector.\n### Properties\n* __Point__ - base point of the ray\n* __Direction__ - direction vector of the ray\n* __ToLine__ - convert ray to line\n### Methods\n* __Copy__ - Creates copy of the object\n* __DistanceTo__ - shortest distance to point, line, segment or other ray\n* __PerpendicularTo__ - point on the perpendicular to the line\n* __IntersectionWith__ - intersection of ray with plane\n* __ProjectionTo__ - orthogonal projection of ray to the plane\n* __IsParallelTo__ - check if two objects are parallel\n* __IsNotParallelTo__ - check if two objects are NOT parallel\n* __IsOrthogonalTo__ - check if two objects are orthogonal\n* __IsCoplanarTo__ - check if ray is coplanar to other linear or planar object\n* __AngleTo__ - angle between two objects\n* __AngleToDeg__ - angle between two objects (in degrees)\n* __Translate__ - translate ray by vector\n* __Rotate__ - rotate ray around origin or other point\n* __Reflect__ - reflect ray in point, line or plane\n* __Equals__ - check if two rays are equals\n* __ToString__ - string representation of ray in global or local coordinate system\n\n## Segment3d\n\nRepresent a line segment in 3D space and is defined by two points.\n### Properties\n* __P1__ - first point of the segment\n* __P2__ - second point of the segment\n* __Length__ - length of the segment\n* __ToVector__ - convert segment to vector\n* __ToRay__ - convert segment to ray\n* __ToLine__ - convert segment to line\n* __MinimumBoundingBox__ - minimum bounding box of the object\n* __BoundingSphere__ - bounding sphere of the object\n### Methods\n* __Copy__ - Creates copy of the object\n* __BoundingBox__ - Axis Aligned Bounding Box (AABB) in given coordinate system\n* __DistanceTo__ - shortest distance to point, line, ray, plane, circle, sphere, triangle, polyhedron or other segment\n* __IntersectionWith__ - intersection of segment with line, plane, ellipse, triangle, ellipsoid, sphere, circle, box or other segment\n* __Intersects__ - intersection check with circle and polyhedron\n* __ProjectionTo__ - orthogonal projection of segment to the line or plane\n* __IsParallelTo__ - check if two objects are parallel\n* __IsNotParallelTo__ - check if two objects are NOT parallel\n* __IsOrthogonalTo__ - check if two objects are orthogonal\n* __IsCoplanarTo__ - check if segment is coplanar to other linear or planar object\n* __AngleTo__ - angle between two objects\n* __AngleToDeg__ - angle between two objects (in degrees)\n* __Translate__ - translate segment by vector\n* __Rotate__ - rotate segment around origin or other point\n* __Reflect__ - reflect segment in point, line or plane\n* __Equals__ - check if two segments are equals\n* __ToString__ - string representation of serment in global or local coordinate system\n\n## Plane3d\n\n3D plane defined by arbutrary point on the plane and a normal vector. \nOptionally can be defined by coefficients in general equation of plane (Ax + By + Cz + D = 0), by three points\nor by point and two vectors in the plane.\n### Properties\n* __Point__ - point on the plane\n* __Normal__ - normal vector of the plane\n* __A/B/C/D__ - coefficients A, B, C and D in the general plane equation\n### Methods\n* __Copy__ - Creates copy of the object\n* __SetCoord__ - set reference coordinate system for general plane equation\n* __IntersectionWith__ - intersection of plane with line, plane, segment, sphere, ellipse, ellipsoid, circle or two other planes\n* __IsParallelTo__ - check if two objects are parallel\n* __IsNotParallelTo__ - check if two objects are NOT parallel\n* __IsOrthogonalTo__ - check if two objects are orthogonal\n* __IsCoplanarTo__ - check if plane is coplanar to other linear or planar object\n* __AngleTo__ - angle between two objects\n* __AngleToDeg__ - angle between two objects (in degrees)\n* __Translate__ - translate plane by vector\n* __Rotate__ - rotate plane around origin or other point\n* __Reflect__ - reflect plane in point, line or plane\n* __Equals__ - check if two planes are equals\n* __ToString__ - string representation of plane in global or local coordinate system\n\n## Sphere\n\nDefines a sphere in 3D space. Implements intersection with line, plane and other sphere, projection to line and plane, as well as\ncommon translation, rotation and reflection methods.\n### Properties\n* __Center__ - center of the sphere\n* __R__ - radius of the sphere\n* __Area__ - area of the sphere\n* __Volume__ - volume of the sphere\n* __MinimumBoundingBox__ - minimum bounding box of the object\n* __BoundingSphere__ - bounding sphere of the object\n### Methods\n* __Copy__ - Creates copy of the object\n* __BoundingBox__ - Axis Aligned Bounding Box (AABB) in given coordinate system\n* __IsInside__ - check if sphere is located inside box\n* __ClosestPoint__ - point on sphere's surface closest to target point\n* __DistanceTo__ - shortest distance to point, line, ray, segment, plane, circle, sphere, polyhedron or box\n* __Intersects__ - intersection check with circle and triangle\n* __IntersectionWith__ - intersection of sphere with line, plane, segment, ray or other sphere\n* __ProjectionTo__ - orthogonal projection of sphere to the line or plane\n* __Translate__ - translate sphere by vector\n* __Rotate__ - rotate sphere around origin or other point\n* __Reflect__ - reflect sphere in point, line or plane\n* __Equals__ - check if two spheres are equals\n* __ToString__ - string representation of sphere in global or local coordinate system\n\n## Circle3d\n\nDefines a circle in 3D space by center point, radius and normal vector.\n### Properties\n* __Center__ - center of the circle\n* __R__ - radius of the circle\n* __Normal__ - normal of the circle\n* __Perimeter__ - perimeter of the circle\n* __Area__ - area of the circle\n* __ToEllipse__ - convert circle to equivalent ellipse\n* __MinimumBoundingBox__ - minimum bounding box of the object\n* __BoundingSphere__ - bounding sphere of the object\n### Methods\n* __Copy__ - Creates copy of the object\n* __BoundingBox__ - Axis Aligned Bounding Box (AABB) in given coordinate system\n* __IsInside__ - check if circle is located inside box\n* __ClosestPoint__ - point on circle's surface closest to target point\n* __ParametricForm__ - return point on circle for given parameter 't'\n* __ProjectionTo__ - orthogonal projection of circle to plane or line\n* __DistanceTo__ - shortest distance to point, plane, circle, sphere, box, polyhedron or triangle\n* __Intersects__ - intersection check with box, triangle, circle and sphere\n* __IntersectionWith__ - intersection of circle with line, plane, segment or other circle\n* __IsParallelTo__ - check if two objects are parallel\n* __IsNotParallelTo__ - check if two objects are NOT parallel\n* __IsOrthogonalTo__ - check if two objects are orthogonal\n* __IsCoplanarTo__ - check if circle is coplanar to other linear or planar object\n* __AngleTo__ - angle between two objects\n* __AngleToDeg__ - angle between two objects (in degrees)\n* __Translate__ - translate circle by vector\n* __Rotate__ - rotate circle around origin or other point\n* __Reflect__ - reflect circle in point, line or plane\n* __Equals__ - check if two circles are equals\n* __ToString__ - string representation of circle in global or local coordinate system\n\n## Ellipse\n\nEllipse in 3D space, defined by center point and two orthogonal vectors, major and minor semiaxes.\n### Properties\n* __Center__ - center of the ellipse\n* __MajorSemiaxis__ - major semiaxis of the ellipse\n* __MinorSemiaxis__ - minor semiaxis of the ellipse\n* __Normal__ - normal of the ellipse\n* __A__ - length of major semiaxis\n* __B__ - length of minor semiaxis\n* __F__ - distance from center to focus\n* __F1__ - first focus\n* __F2__ - second focus\n* __e__ - eccentricity of the ellipse\n* __Perimeter__ - approximate circumference of the ellipse\n* __Area__ - area of the ellipse\n* __MinimumBoundingBox__ - minimum bounding box of the object\n* __BoundingSphere__ - bounding sphere of the object\n### Methods\n* __Copy__ - Creates copy of the object\n* __BoundingBox__ - Axis Aligned Bounding Box (AABB) in given coordinate system\n* __ParametricForm__ - return point on ellipse for given parameter 't'\n* __ProjectionTo__ - orthogonal projection of ellipse to plane or line\n* __IntersectionWith__ - intersection of ellipse with line, plane or segment\n* __ClosestPoint__ - calculates the point on the ellipse's boundary closest to given point\n* __IsParallelTo__ - check if two objects are parallel\n* __IsNotParallelTo__ - check if two objects are NOT parallel\n* __IsOrthogonalTo__ - check if two objects are orthogonal\n* __IsCoplanarTo__ - check if ellipse is coplanar to other linear or planar object\n* __AngleTo__ - angle between two objects\n* __AngleToDeg__ - angle between two objects (in degrees)\n* __Translate__ - translate ellipse by vector\n* __Rotate__ - rotate ellipse around origin or other point\n* __Reflect__ - reflect ellipse in point, line or plane\n* __Equals__ - check if two ellipses are equals\n* __ToString__ - string representation of ellipse in global or local coordinate system\n\n## Ellipsoid\n\nEllipsoid object defined by center point and three mutually orthogonal vectors.\n### Properties\n* __Center__ - center of the ellipsoid\n* __SemiaxisA/B/C__ - semiaxes of the ellipsoid\n* __A/B/C__ - length of the semiaxes of the ellipsoid\n* __Area__ - approximate surface area of the ellipsoid\n* __Volume__ - volume of the ellipsoid\n* __MinimumBoundingBox__ - minimum bounding box of the object\n* __BoundingSphere__ - bounding sphere of the object\n### Methods\n* __Copy__ - Creates copy of the object\n* __BoundingBox__ - Axis Aligned Bounding Box (AABB) in given coordinate system\n* __ProjectionTo__ - orthogonal projection of ellipsoid to line\n* __IntersectionWith__ - intersection of ellipsoid with line, plane or segment\n* __Intersects__ - intersection check with sphere\n* __DistanceTo__ - distance to other ellipsoid\n* __ClosestPoint__ - calculates the point on the ellipsoid's boundary closest to given point\n* __Translate__ - translate ellipsoid by vector\n* __Rotate__ - rotate ellipsoid around origin or other point\n* __Reflect__ - reflect ellipsoid in point, line or plane\n* __Equals__ - check if two ellipsoids are equals\n* __ToString__ - string representation of ellipsoid in global or local coordinate system\n\n## Box3d\n\nBox object defined by center point, three dimensions and orientation in space.\n### Properties\n* __Center__ - center point of the box\n* __L1/L2/L3__ - dimensions of the box\n* __V1/V2/V3__ - orientation vectors of the box\n* __Orientation__ - box orientation\n* __P1/P2/P3/P4/P5/P6/P7/P8__ - corner points of the box\n* __ListOfPoints__ - list of corner points of the box\n* __ListOfTriangles__ - list of triangles forming the box's surface\n* __ListOfPlanes__ - list of planes forming the box's surface\n* __ListOfEdges__ - list of edges\n* __Area__ - area of the box\n* __Volume__ - volume of the box\n* __MinimumBoundingBox__ - minimum bounding box of the object\n* __BoundingSphere__ - bounding sphere of the object\n* __IsAxisAligned__ - check if box is AABB\n### Methods\n* __Copy__ - Creates copy of the object\n* __BoundingBox__ - Axis Aligned Bounding Box (AABB) in given coordinate system\n* __DistanceTo__ - shortest distance to point, circle or sphere\n* __Intersects__ - intersection check with box, circle, tetrahedron or triangle\n* __IntersectionWith__ - intersection of box with line, ray or segment\n* __Translate__ - translate box by vector\n* __Rotate__ - rotate box around origin or other point\n* __Reflect__ - reflect box in point, line or plane\n* __Equals__ - check if two ellipsoids are equals\n* __ToString__ - string representation of ellipsoid in global or local coordinate system\n### Static Methods\n* __AABB__ - axis aligned bounding box for a cloud of points\n\n## AABB\n\nAxis aligned 3D box, can be degenerated with one or more dimensions equal 0. Defined only in Global CS.\n### Properties\n* __Center__ - center point of the box\n* __L1/L2/L3__ - dimensions of the box\n* __V1/V2/V3__ - orientation vectors of the box\n* __Orientation__ - box orientation\n* __P1/P2/P3/P4/P5/P6/P7/P8__ - corner points of the box\n* __Xmin/Xmax/Ymin/Ymax/Zmin/Zmax__ - boundaries of the AABB\n* __ListOfPoints__ - list of corner points of the box\n* __ListOfTriangles__ - list of triangles forming the box's surface\n* __ListOfPlanes__ - list of planes forming the box's surface\n* __ListOfEdges__ - list of edges\n* __Area__ - area of the box\n* __Volume__ - volume of the box\n### Methods\n* __Union__ - union of two AABB\n* __DistanceTo__ - shortest distance to point, AABB, circle or sphere\n* __ClosestPoint__ - calculates the point on the AABB closest to given point\n* __Intersects__ - intersection check with AABB, box, circle, or triangle\n* __IntersectionWith__ - intersection of box with AABB, line, ray or segment\n* __Translate__ - translate box by vector\n* __Rotate__ - rotate box around origin or other point\n* __Reflect__ - reflect box in point, line or plane\n* __Equals__ - check if two ellipsoids are equals\n* __ToString__ - string representation of ellipsoid in global or local coordinate system\n\n## Triangle\n\nDefines a triangle in 3D space. Implements common translation, rotation and reflection methods. Calculates most of the standard\ntriangle properties: bisectors, meadians, altitudes, incenter, circumcenter, centroid, orthocenter, etc.\n### Properties\n* __A/B/C__ - vertices of the triangle\n* __AB/AC/BC__ - length of the triangles' sides\n* __Perimeter__ - perimeter of the triangle\n* __Area__ - area of the triangle\n* __Circumcircle__ - circumcircle of the triangle\n* __Angle_A/B/C__ - angle at the vertex A/B/C\n* __Bisector_A/B/C__ - angle bisector at the vertex A/B/C\n* __Incenter__ - incenter of the triangle\n* __Centroid__ - centroid of the triangle\n* __Orthocenter__ - orthocenter of the triangle\n* __Circumcenter__ - circumcenter of the triangle\n* __Incircle__ - incircle of the triangle\n* __Altitude_A/B/C__ - altitude at the vertex A/B/C\n* __Median_A/B/C__ - median at the vertex A/B/C\n* __IsEquilateral__ - check if all sides of the triangle are the same length\n* __IsIsosceles__ - check if two sides of the triangle are the same length\n* __IsScalene__ - check if all sides are unequal\n* __IsRight__ - check if one angle is equal 90 degrees\n* __IsObtuse__ - check if one angle is greater than 90 degrees\n* __IsAcute__ - check if all angles are less than 90 degrees\n* __MinimumBoundingBox__ - minimum bounding box of the object\n* __BoundingSphere__ - bounding sphere of the object\n### Methods\n* __Copy__ - Creates copy of the object\n* __BoundingBox__ - Axis Aligned Bounding Box (AABB) in given coordinate system\n* __DistanceTo__ - shortest distance to point, segment, triangle and circle\n* __IntersectionWith__ - intersection of triangle with line, plane, ray or segment\n* __Intersects__ - intersection check with triangle, box, tetrahedron, sphere, polyhedron or circle\n* __ProjectionTo__ - orthogonal projection of triangle to line\n* __IsParallelTo__ - check if two objects are parallel\n* __IsNotParallelTo__ - check if two objects are NOT parallel\n* __IsOrthogonalTo__ - check if two objects are orthogonal\n* __IsCoplanarTo__ - check if triangle is coplanar to other linear or planar object\n* __AngleTo__ - angle between two objects\n* __AngleToDeg__ - angle between two objects (in degrees)\n* __Translate__ - translate triangle by vector\n* __Rotate__ - rotate triangle around origin or other point\n* __Reflect__ - reflect triangle in point, line or plane\n* __Equals__ - check if two triangles are equals\n* __ToString__ - string representation of triangle in global or local coordinate system\n\n## Tetrahedron\n\nDefines a tetrahedron in 3D space. Implements common translation, rotation and reflection methods.\n### Properties\n* __A/B/C/D__ - vertices of the tetrahedron\n* __Center__ - center of the mass of tetrahedron\n* __ListOfEdges__ - list of edges\n* __ListOfFaces__ - list of faces\n* __Area__ - area of the tetrahedron\n* __Volume__ - volume of the tetrahedron\n### Methods\n* __Copy__ - Creates copy of the object\n* __BoundingBox__ - bounding box in given coordinate system\n* __AABB__ - Axis Aligned Bounding Box (AABB)\n* __DistanceTo__ - shortest distance to point and tetrahedron\n* __ClosestPoint__ - calculates the point on the terahedron's boundary closest to given point\n* __Intersects__ - intersection check with triangle, tetrahedron, line, ray, segment, box and sphere\n* __IsInside__ - check if object is located inside given box\n* __Translate__ - translate tetrahedron by vector\n* __Rotate__ - rotate tetrahedron around origin or other point\n* __Reflect__ - reflect tetrahedron in point, line or plane\n* __Scale__ - scale tetrahedron\n* __Equals__ - check if two tetrahedrons are equals\n* __ToString__ - string representation of tetrahedron in global or local coordinate system\n\n## ConvexPolyhedron\n\nDefines a convex polyhedron in 3D space with counterclockwise oriented faces (seen from outside).\n### Properties\n* __Center__ - center of the mass of polyhedron\n* __ListOfEdges__ - list of edges\n* __Area__ - area of the polyhedron\n* __Volume__ - volume of the polyhedron\n### Methods\n* __Copy__ - Creates copy of the object\n* __BoundingBox__ - bounding box in given coordinate system\n* __AABB__ - Axis Aligned Bounding Box (AABB)\n* __DistanceTo__ - shortest distance to point, circle, sphere, segment, triangle, and polyhedron\n* __Intersects__ - intersection check with polyhedron, segment, triangle and box\n* __IsInside__ - check if object is located inside given box\n* __Translate__ - translate polyhedron by vector\n* __Rotate__ - rotate polyhedron around origin or other point\n* __Scale__ - scale polyhedron\n### Static Methods\n* __FromTetrahedron__ - Create ConvexPolyhedron object from a Tetrahedron object\n* __FromBox__ - Create ConvexPolyhedron object from a Box3d object\n* __Octahedron__ - Creates regular octahedron centered at origin\n* __Icosahedron__ - Creates regular icosahedron centered at origin\n* __Dodecahedron__ - Creates regular dodecahedron centered at origin\n* __RhombicDodecahedron__ - Creates rhombic dodecahedron centered at origin\n* __Cuboctahedron__ - Creates cuboctahedron centered at origin\n* __Rhombicuboctahedron__ - Creates rhombicuboctahedron centered at origin\n* __ToString__ - string representation of polyhedron in global or local coordinate system\n\n\n## Coord3d\n\nClass representing orthogonal cartesian 3D coordinate system. Defined by an origin point and transformation matrix\n(three orthogonal unit vectors stored in row format). One global coordinate system (Coord3d.GlobalCS) is defined by default,\nany number of local coordinate systems can be defined by users.\n### Properties\n* __Origin__ - origin of the coordinate system\n* __Axes__ - unit vectors of the axes, stored as row-matrix(3x3)\n* __Name__ - name of the coordinate system\n* __Counts__ - total number of defined coordinate systems\n* __X/Y/Zaxis__ - X/Y/Z-axis of the coordinate system\n* __XY/XZ/YZ_plane__ - planes of the coordinate system\n### Methods\n* __Copy__ - Creates copy of the object\n* __Rotate/RotateDeg__ - rotate coordinate system around rotation axis\n* __Equals__ - check if two coordinate systems are equals\n* __ToString__ - string representation of coordinate system\n\n## Matrix3d\n\n### Properties\n* __Item(i,j)__ - element of the matrix\n* __Row1/2/3__ - rows of the matrix\n* __Column1/2/3__ - columns of the matrix\n* __Det__ - determinant of the matrix\n* __MaxNorm__ - Max norm of the matrix\n* __IsZero__ - check if matrix is zero matrix\n* __IsIdentity__ - check if matrix is identity matrix\n* __IsOrthogonal__ - check if matrix is orthogonal\n### Methods\n* __Inverse__ - inverse of the matrix\n* __Transpose__ - transpose of the matrix\n* __RotationMatrix__ - rotation around given axis\n* __Equals__ - check if two matrix are equals\n* __ToString__ - string representation of matrix\n### Static methods\n* __Identity__ - creates new identity matrix\n* __DiagonalMatrix__ - creates diagonal matrix\n\n## Quaternion\nUnit quaternion (W + X*i + Y*j + Z*k)\n### Properties\n* __W/X/Y/Z__ - components of quaternion in reference coordinate system\n* __Coord__ - reference coordinate system\n* __Norm__ - norm of a quaternion\n* __SquareNorm__ - square of the norm of a quaternion\n* __Conjugate__ - conjugate of a quaternion\n* __ToAxis__ - axis of rotation in reference coordinate system\n* __ToAngle__ - angle of rotation in reference coordinate system\n* __Normalized__ - return normalized quaternion\n### Methods\n* __Copy__ - Creates copy of the object\n* __ConvertTo__ - convert quaternion to local coordinate system\n* __ConvertToGlobal__ - convert quaternion to global coordinate system\n* __Normalize__ - normalize the current quaternion\n* __Add/Subtract/Mult__ - arithmetic operations\n* __Scale__ - scale quaternion by number\n* __Inverse__ - inverse quaternion\n* __ToRotationMatrix__ - convert to rotation matrix\n* __Equals__ - check if two quaternions are equals\n* __ToString__ - string representation of quaternion in global or local coordinate system\n### Static methods\n* __SLERP__ - Spherical Linear intERPolation of two quaternions\n\n## Rotation\nRotation in 3D space defined in global or local reference frame (internally represented by rotation matrix)\n### Properties\n* __Coord__ - reference coordinate system\n* __ToAxis__ - axis of rotation in reference coordinate system\n* __ToAngle__ - angle of rotation in reference coordinate system\n* __ToRotationMatrix__ - rotation matrix\n* __ToQuaternion__ - convert to quaternion\n### Methods\n* __Copy__ - Creates copy of the object\n* __ConvertTo__ - convert rotation to local coordinate system\n* __ConvertToGlobal__ - convert rotation to global coordinate system\n* __Mult__ - apply rotation to point or vector\n* __ToEulerAngles__ - factor rotation matrix as product of three elemental rotations\n* __Equals__ - check if two rotations are equals\n* __ToString__ - string representation of rotation in global or local coordinate system\n### Static methods\n* __FromEulerAngles__ - creates rotation object from Euler or Tait-Bryan angles\n* __SLERP__ - Spherical Linear intERPolation of two rotations\n\n## GeometRi3D\n\n### Properties\n* __Tolerance__ - tolerance used for comparison operations (default 1e-12)\n### Methods\n* __AlmostEqual__ - tolerance based equality check\n* __NotEqual__ - tolerance based unequality check\n* __Greater__ - tolerance based comparison\n* __Smaller__ - tolerance based comparison\n\n## Credits\n\nSome of the algorithms were ported from [Geometric Tools](https://www.geometrictools.com/) developed by David Eberly and available under the Boost license, available [here](https://www.geometrictools.com/Downloads/Downloads.html)\n\nOther algorithms were adapted from these sources:\n* Amy Williams, Steve Barrus, R. Keith Morley, Peter Shirley \"An Efficient and Robust Ray–Box Intersection Algorithm\" [PDF](https://people.csail.mit.edu/amy/papers/box-jgt.pdf)\n* Stephen B. Pope \"Algorithms for Ellipsoids\" [PDF](https://tcg.mae.cornell.edu/pubs/Pope_FDA_08.pdf)\n* [https://www.ambrbit.com/TrigoCalc/Circles2/Ellipse/EllipseLine.htm](https://www.ambrbit.com/TrigoCalc/Circles2/Ellipse/EllipseLine.htm)\n* Robert Nurnberg \"Distance from a Point to an Ellipse/Ellipsoid\" [PDF](https://nurnberg.maths.unitn.it/distance2ellipse.pdf)\n* Johannes Buchner [line - ellipsoid intersection](https://johannesbuchner.github.io/intersection/intersection_line_ellipsoid.html)\n* Peter Paul Klein \"On the Ellipsoid and Plane Intersection Equation\", Applied Mathematics, 2012, 3, 1634-1640 (DOI:10.4236/am.2012.311226)\n* Sebahattin Bektas \"Intersection of an Ellipsoid and a Plane\", International Journal of Research in Engineering and Applied Sciences, VOLUME 6, ISSUE 6 (June, 2016)\n* Wang, W., Wang, J., & Kim, M. S. (2001). An algebraic condition for the separation of two ellipsoids. Computer aided geometric design, 18(6), 531-539.\n* Dan Sunday [URL](http://geomalgorithms.com/a07-_distance.html)\n* Möller–Trumbore intersection algorithm [URL](https://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm)\n"
  },
  {
    "path": "ReleaseNotes.md",
    "content": "# GeometRi\n## Release notes\n\n### 1.5.0.8 (19/03/2026)\n* Fixed triangle-segment intersection.\n* Union of two AABB.\n* Small optimizations.\n\n### 1.5.0.7 (17/10/2025)\n* Optimization of polyhedron distance/intersection calculations.\n* Optimization of circle distance calculations.\n\n### 1.5.0.5 (22/9/2025)\n* Fixed null reference error in multi-threaded applications.\n* Small optimizations.\n\n### 1.5.0.4 (5/9/2025)\n* Optimizations of polyhedron distance calculations.\n* Intersection check of polyhedron, segment, and triangle.\n* Fixed polyhdron-polyhedron distance calculation.\n\n### 1.5.0.3 (2/9/2025)\n* Optimizations of distance calculations for various objects.\n\n### 1.5.0.2 (29/8/2025)\n* Added DistanceSquared() method for primitive objects.\n\n### 1.5.0 (24/8/2025)\n* Caching of some computed object's properties.\n* Reference is returned instead of object's copy.\n* Möller-Trumbore triangle-ray intersection algorithm.\n* Other optimizations.\n\n### 1.4.1.4 (13/7/2025)\n* Intersection check of ellipsoid and sphere.\n* Distance between two ellipsoids.\n\n### 1.4.1.3 (27/5/2025)\n* Fixed AABB local coordinate system.\n* Create prism by extruding face of convex polyhedron.\n\n### 1.4.1.2 (5/3/2025)\n* Distance from convex polyhedron to segment, sphere, and circle.\n* Several optimizations.\n\n### 1.4.1.1 (24/10/2024)\n* Fixed closest points locations in ConvexPoly distance calculations.\n* Fixed circle-circle intersection check.\n\n### 1.4.1.0 (16/4/2024)\n* Convex polyhedron class.\n* Axis aligned bounding box (AABB) class.\n\n### 1.4.0.1 (13/9/2022)\n* Fixed segment direction normalization.\n\n### 1.4.0.0 (8/9/2022)\n* Added tetrahedron class.\n* More robust traingle and plane/line intersection algorithm.\n* Breaking changes: Line.PerpendicuarTo(Line) now returns 'null' for parallel lines.\n\n### 1.3.5.16 (7/5/2021)\n* Fixed distance from triangle to point calculation.\n\n### 1.3.5.15 (1/6/2021)\n* Intersection check of triangle with triangle and box.\n\n### 1.3.5.13 (1/10/2019)\n* Many optimizations.\n* Distance from line to circle's boundary.\n* Fixed circle/triangle intersection check.\n\n### 1.3.5.12 (18/6/2019)\n* Fixed \"Rotation.ToAxis/Angle\" method.\n\n### 1.3.5.11 (17/5/2019)\n* More robust implementation of Point3d.BelongsTo(Segment3d).\n\n### 1.3.5.10 (14/5/2019)\n* Added \"Serializable\" attribute for .Net Framework 2.0 build.\n* Fixed bug in circle/circle intersection.\n\n### 1.3.5.9 (14/3/2019)\n* Shortest distance calculation for various objects.\n\n### 1.3.5.8 (10/1/2019)\n* Distance from sphere to point, plane, circle or other sphere.\n* Closest points on two circles/spheres calculation.\n\n### 1.3.5.7 (15/12/2018)\n* Distance from circle to point, plane or other circle.\n\n### 1.3.5.6 (12/12/2018)\n* Added Circle.IsInside(Box) method.\n* Fixed segment with segment intersection method.\n\n### 1.3.5.5 (2/11/2018)\n* Coplanarity test for different objects.\n\n### 1.3.5.4 (14/10/2018)\n* Fixed point in triangle test.\n\n### 1.3.5.3 (15/9/2018)\n* Box3d intersection with line, ray or segment.\n* Box3d translate, rotate, reflect methods.\n\n### 1.3.5.2 (7/7/2018)\n* Ray3d intersection with line, segment, circle, ellipse, sphere, ellipsoid and triangle.\n\n### 1.3.5.1 (30/6/2018)\n* Added circle-circle intersection method.\n\n### 1.3.5 (20/6/2018)\n* New intersection methods: line/segment intersection with circle, ellipse, triangle, ellipsoid.\n\n### 1.3.4 (4/5/2018)\n* New test methods to check if point is located in the epsilon neighborhood of the object.\n\n### 1.3.3 (21/4/2018)\n* Added relative tolerance equality checks.\n\n### 1.3.2 (27/11/2017)\n* Changed behavior of \"new Vector3d(point)\" and \"Point3d.ToVector\" methods. By default vectors in global CS will be created.\n* Fixed \"Segment3d.DistanceTo(Segment3d)\" (tolerance parameter decreased).\n\n### 1.3.1 (6/10/2017)\n* Added \"Rotation.ToEulerAngles()\" method.\n\n### 1.3.0 (18/9/2017)\n* Added \"Box3d\" class and \"BoundingBox\" methods.\n\n### 1.2.1 (11/9/2017)\n* Added \"Rotation.SLERP\" and \"Rotation.FromEulerAngles\" methods.\n\n### 1.2.0 (26/8/2017)\n* Added \"Rotation\" and \"Quaternion\" classes.\n\n### 1.1.1 (4/8/2017)\n\n### 1.1.0 (30/7/2017)\n\n### 1.0.1 (23/7/2017)\n\n### 0.9.6 (21/6/2017)\n\n### 0.9.5 (3/6/2017)\n\n### 0.9.4 (31/5/2017)\n\n### 0.9.3 (21/5/2017)\n\n### 0.9.2 (29/4/2017)\n\n### 0.9.1 (25/4/2017)\n\n### 0.9.0 (23/4/2017)\n"
  },
  {
    "path": "ToDo.txt",
    "content": "Watertight Ray/Triangle Intersection:\nhttps://jcgt.org/published/0002/01/05/paper.pdf\n\n"
  }
]