private static bool IsTheProjectionInsideOfTheFace(FootprintFace f, Edge edge)
        {
            var    edgeVec      = edge.From.Position.subtract(edge.To.Position).normalize();
            var    comVer       = f.COMP.Position.subtract(edge.To.Position).normalize();
            Vertex vertexOnFace = null;

            foreach (var e in f.OuterEdges)
            {
                if (e == edge)
                {
                    continue;
                }
                if (1 - Math.Abs(e.From.Position.subtract(edge.To.Position).normalize().dotProduct(edgeVec)) > 1e-8)
                {
                    vertexOnFace = e.From;
                    break;
                }
                if (1 - Math.Abs(e.To.Position.subtract(edge.To.Position).normalize().dotProduct(edgeVec)) > 1e-8)
                {
                    vertexOnFace = e.To;
                    break;
                }
            }
            if (vertexOnFace == null)
            {
                return(false);
            }
            var faceVerVec = vertexOnFace.Position.subtract(edge.To.Position).normalize();

            return(edgeVec.crossProduct(comVer).dotProduct(edgeVec.crossProduct(faceVerVec)) > 0);
        }
        public static double CheckStabilityForReference(SubAssembly newSubAsm, FootprintFace f)
        {
            var refCOM = newSubAsm.Install.Reference.CenterOfMass;

            CenterOfMassProjectionOnFootprintFace(f, refCOM);

            f.MinDisNeaEdg = double.PositiveInfinity;
            var x02 = f.COMP.Position[0];
            var y02 = f.COMP.Position[1];
            var z02 = f.COMP.Position[2];

            f.Height = Math.Sqrt(Math.Pow(x02 - refCOM.Position[0], 2) +
                                 Math.Pow(y02 - refCOM.Position[1], 2) +
                                 Math.Pow(z02 - refCOM.Position[2], 2));
            foreach (var edge in f.OuterEdges)
            {
                var edgeVector = edge.From.Position.subtract(edge.To.Position).normalize();
                var distanceOfEdgeToComProj = GeometryFunctions.DistanceBetweenLineAndVertex(edgeVector,
                                                                                             edge.From.Position, f.COMP.Position);
                if (distanceOfEdgeToComProj < f.MinDisNeaEdg)
                {
                    f.MinDisNeaEdg    = distanceOfEdgeToComProj;
                    f.IsComInsideFace = IsTheProjectionInsideOfTheFace(f, edge);
                }
            }
            var spf = Math.Pow(((2 / Math.PI) * (Math.Atan(f.Height / f.MinDisNeaEdg))), 2);

            f.RefS = spf;
            return(f.RefS);
        }
        private static void CenterOfMassProjectionOnFootprintFace(FootprintFace f, Vertex refCOM)
        {
            // For calculating the projection of COM on current New face, we have normal,
            // we have the position of COM and we have points on the edge.
            // First We are looking for the parameters in this plane equation:
            // a(x-x0) + b(y-y0) + c(z-z0) = 0 plane equation or "ax + bY + cz = d"
            var pointOnPlane = f.OuterEdges[0].From.Position;
            var norm         = f.Normal;
            var com          = refCOM.Position;
            var t            = (norm[0] * (pointOnPlane[0] - com[0]) + norm[1] * (pointOnPlane[1] - com[1]) +
                                norm[2] * (pointOnPlane[2] - com[2])) / (norm[0] * norm[0] + norm[1] * norm[1] + norm[2] * norm[2]);

            f.COMP = new Vertex(new[] { com[0] + t * norm[0], com[1] + t * norm[1], com[2] + t * norm[2] });
        }
        public static double CheckAccessability(double[] installDirection, FootprintFace f)
        {
            var angleBetweenInsDirAndNormal = Math.Abs(installDirection.normalize().dotProduct(f.Normal));

            return(2 - (angleBetweenInsDirAndNormal / Math.PI) * 2.0);
        }