Beispiel #1
0
        public IEnumerable <ISimpliceFacet> GetFacetOrNull(INuclei n1, INuclei n2)
        {
            IEnumerable <BowyerSimplice> intersectionSimplices = ((BowyerNuclei)n1).simplices.Where(s => s.nucleis.Contains(n2));
            var facetsA = intersectionSimplices.Select(s => s.Facets.SingleOrDefault(f => f.Nucleis.Contains(n2) && f.Nucleis.Contains(n1)))
                          .Where(f => f != null);

            return(facetsA);
        }
Beispiel #2
0
        internal void Calculate(IEnumerable <INuclei> Nucleis, int problemDimensionality, int nucleisCount)
        {
            Helpers.CalculateSimpliceCentroidFromFacets(Nucleis, nucleisCount - 1, ref Center);
            INuclei nuclei = Nucleis.First();

            //now calculate the radious and store it.
            Vector v = new Vector(problemDimensionality);

            for (int i = 0; i < problemDimensionality; i++)
            {
                v[i] = Center[i] - nuclei.Coordinates[i];
            }

            this.Radious = v.Norm();
        }
            /// <summary>
            /// Constraint is created as a bound between these two points. A line-bound in 2D case, a Plane in the 3D case and a hyperplane in ND case.
            /// It represents a single inequality that checks if a sample point belong to the positive or negative subspaces.
            /// </summary>
            /// </param>
            public DefaultVoronoiFacet(INuclei ownerNuclei, INuclei foreignNuclei)
            {
                this.Owner = ownerNuclei;
                this.External = foreignNuclei;
                double[] ownerPoint = Owner.Coordinates;
                double[] foreignPoint = External.Coordinates;

                double[] coefficents = new Vector(ownerPoint.Length + 1) ;
                coefficents[coefficents.Length - 1] = 0;

                //calculating coefficents except the independent coefficent
                for (int i = 0; i < ownerPoint.Length; i++) {
                coefficents[i] = ownerPoint[i] - foreignPoint[i];
                //calculating the independent coefficent
                coefficents[coefficents.Length - 1] -= coefficents[i] * ((foreignPoint[i] + ownerPoint[i]) / 2f);
                }
                this.constraint = new HyperPlaneConstraint(coefficents);
            }
Beispiel #4
0
        internal static int CalculatePointsRank(IEnumerable <INuclei> points)
        {
            INuclei first                   = points.First();
            int     pointsCount             = first.Simplices.First().Rank + 2;
            Matrix  vectors                 = new Matrix(pointsCount - 1, first.Coordinates.Length);
            IEnumerator <INuclei> currPoint = points.GetEnumerator();

            currPoint.MoveNext();

            for (int i = 0; i < vectors.RowCount && currPoint.MoveNext(); i++)
            {
                for (int j = 0; j < vectors.ColumnCount; j++)
                {
                    vectors[i, j] = first.Coordinates[j] - currPoint.Current.Coordinates[j];
                }
            }

            return(vectors.Rank());
        }
Beispiel #5
0
            /// <summary>
            /// Constraint is created as a bound between these two points. A line-bound in 2D case, a Plane in the 3D case and a hyperplane in ND case.
            /// It represents a single inequality that checks if a sample point belong to the positive or negative subspaces.
            /// </summary>
            /// </param>
            public DefaultVoronoiFacet(INuclei ownerNuclei, INuclei foreignNuclei)
            {
                this.Owner    = ownerNuclei;
                this.External = foreignNuclei;
                double[] ownerPoint   = Owner.Coordinates;
                double[] foreignPoint = External.Coordinates;

                double[] coefficents = new Vector(ownerPoint.Length + 1);
                coefficents[coefficents.Length - 1] = 0;

                //calculating coefficents except the independent coefficent
                for (int i = 0; i < ownerPoint.Length; i++)
                {
                    coefficents[i] = ownerPoint[i] - foreignPoint[i];
                    //calculating the independent coefficent
                    coefficents[coefficents.Length - 1] -= coefficents[i] * ((foreignPoint[i] + ownerPoint[i]) / 2f);
                }
                this.constraint = new HyperPlaneConstraint(coefficents);
            }
Beispiel #6
0
        internal static Vector[] VectorsFromPoints(IEnumerable <INuclei> points, int pointsCount)
        {
            Vector[] vectors = new Vector[pointsCount - 1];
            IEnumerator <INuclei> currentPoint = points.GetEnumerator();

            currentPoint.MoveNext();
            INuclei first = currentPoint.Current;

            int dimensionality = first.Coordinates.Length;

            for (int i = 0; currentPoint.MoveNext(); i++)
            {
                vectors[i] = new Vector(dimensionality);
                for (int j = 0; j < first.Coordinates.Length; j++)
                {
                    vectors[i][j] = currentPoint.Current.Coordinates[j] - first.Coordinates[j];
                }
            }
            return(vectors);
        }
Beispiel #7
0
        public IVoronoiRegion AddNewPoint(object data, double[] newPoint)
        {
            if (newPoint == null || newPoint.Length != ProblemDimensionality)
            {
                throw new ArgumentException("point added null or has invalid dimensionality");
            }

            BowyerNuclei newNuclei = new BowyerNuclei(newPoint);

            newNuclei.Data = data;

            //SPECIAL CASE FOR FIRST ADD
            if (!voronoiVertexes.Any())
            {
                //no voronoiVertexes
                //no simplices
                //no regions

                BowyerNuclei[] nucleis = new BowyerNuclei[1];
                newNuclei      = nucleis[0] = new BowyerNuclei(newPoint);
                newNuclei.Data = data;

                //create a VoronoiVertex in the infinite
                var voronoiVertex = new BowyerVoronoiVertex(0, nucleis, new HyperSphereConstraint(newNuclei.Coordinates, double.PositiveInfinity));

                this.voronoiVertexes.Add(voronoiVertex);
                this.nucleis.Add(newNuclei);

                //create a not formed Simplice
                return(voronoiVertexes.First().Simplice.Nucleis.First().VoronoiHyperRegion);
            }
            else
            {
                //--------------- SITUATION ANALYSIS - READ ONLY--------------

#warning optimizable: not variable list without cast, external auxiliar attribute
                List <BowyerVoronoiVertex> affectedVertexes = new List <BowyerVoronoiVertex>();
#warning optimizable: not variable list without cast, external auxiliar attribute
                List <BowyerNuclei> affectedNucleis = new List <BowyerNuclei>();


                IEnumerable <INuclei> newpointSet = new INuclei[] { newNuclei };

#warning optimizable: cant be this an auxiliar attribute?
                var secondaryAffecteVertexes = new List <BowyerSimpliceFacet>();


                if (nucleisRank < ProblemDimensionality && Helpers.CalculatePointsRank(Simplices.First().Nucleis.Union(newpointSet)) > nucleisRank)
                {
                    affectedVertexes = this.voronoiVertexes;
                    nucleisRank++;
                    foreach (var v in affectedVertexes)
                    {
                        v.IsTrash = true;
                    }

#warning optimize, eliminate the cast and create a nuclei List
                    affectedNucleis.AddRange(this.Nucleis.Cast <BowyerNuclei>());
                }
                else
                {
                    IVoronoiRegion r = GetMatchingRegion(newPoint);
                    // and use r.Vertexes
                    foreach (BowyerVoronoiVertex v in r.Vertexes)
                    {
                        if (v.Simplice.CircumsphereContains(newPoint))
                        {
                            if (!affectedVertexes.Contains(v))
                            {
                                affectedVertexes.Add(v);
                                v.IsTrash = true;
                                foreach (var affectedNuclei in v.simplice.nucleis)
                                {
                                    if (!affectedNucleis.Contains(affectedNuclei))
                                    {
                                        affectedNucleis.Add(affectedNuclei);
                                    }
                                }
                            }

                            foreach (var vaffected in v.simplice.facets.Where(f => f.External.Infinity).Select(f => (BowyerVoronoiVertex)f.External))
                            {
                                if (!affectedVertexes.Contains(vaffected))
                                {
                                    affectedVertexes.Add(vaffected);
                                    vaffected.IsTrash = true;
                                }
                            }

                            foreach (var otherAffectedFace in v.simplice.facets.Where(f => !f.External.Infinity))
                            {
                                if (!affectedVertexes.Contains((BowyerVoronoiVertex)otherAffectedFace.External) && !secondaryAffecteVertexes.Contains(otherAffectedFace))
                                {
                                    secondaryAffecteVertexes.Add(otherAffectedFace);
                                }
                            }


                            //add also all the infinite vertexes if it or neighbours who contains it
                            //foreach (var vneigh2 in v.simplice.facets
                            //                                      .Where(f => !affectedVertexes.Contains((BowyerVoronoiVertex)f.External)
                            //                                                  && (f.External.Infinity
                            //                                                     || f.External.Simplice.CircumsphereContains(newPoint)))
                            //                                      .Select(f => (BowyerVoronoiVertex)f.External))
                            //{
                            //    vneigh2.IsTrash = true;
                            //    affectedVertexes.Add(vneigh2);

                            //}
                        }
                    }
                }



                //if (!affectedVertexes.Any())
                //{
                //    //if no normal simplices contains the new point
                //    //we will to try it in infinite vertexs of this region
                //    foreach (BowyerVoronoiVertex v in r.Vertexes.Where(v => v.Infinity))
                //        if (v.Simplice.CircumsphereContains(newPoint))
                //        {
                //            affectedVertexes.Add(v);
                //            v.IsTrash = true;
                //            affectedNucleis.AddRange(v.simplice.nucleis);

                //            //add to affected vertexes also the only neighbour vertex of
                //            //the current infinite vertex
                //            BowyerVoronoiVertex vnormal = (BowyerVoronoiVertex)v.simplice.facets.Single().External;
                //            secondaryAffecteVertexes.Add(vnormal);

                //            //vnormal.IsTrash = true;
                //            //affectedVertexes.Add(vnormal);
                //            ////add also all the infinite vertexes if it or neighbours who contains it
                //            //foreach (var vneigh2 in vnormal.simplice.facets.Select(f => (BowyerVoronoiVertex)f.External)
                //            //                                               .Where(v2 => v2 != v && !affectedVertexes.Contains(v2)
                //            //                                                   && (v2.Infinity || v2.simplice.CircumsphereContains(newPoint))))
                //            //{
                //            //    vneigh2.IsTrash = true;
                //            //    affectedVertexes.Add(vneigh2);
                //            //}

                //      }
                //  }

                // }

#if DEBUG
                Debug.Print(string.Format("{0} ||| adding new point. Affected vertexes: {1}. Secondary Affected vertexes: {2}", this.ToString(), affectedVertexes.Count, secondaryAffecteVertexes.Count));

                if (!affectedVertexes.Any())
                {
                    throw new ArgumentException("this case is not possible and has not been contemplated");
                }

                if (affectedVertexes.Distinct().Count() != affectedVertexes.Count)
                {
                    throw new ArgumentException("Incoherence in the algorithm");
                }

                if (affectedNucleis.Distinct().Count() != affectedNucleis.Count)
                {
                    throw new ArgumentException("Incoherence in the algorithm");
                }

                if (secondaryAffecteVertexes.Distinct().Count() != secondaryAffecteVertexes.Count)
                {
                    throw new ArgumentException("Incoherence in the algorithm");
                }
#endif


                //if any candidate vertex sismplice has the maxium dimensionality, the postgenerated tesellation will also have this maxium dimensionality

                //if (affectedVertexes.First().Simplice.Dimensionality == ProblemDimensionality)
                //    nucleisRank = ProblemDimensionality;
                //else
                //    nucleisRank = Helpers.CalculatePointsRank(affectedNucleisArray);



                //--------------------- CLEARING EXISTING DATA --------------------------------------

                foreach (var f in secondaryAffecteVertexes)
                {
                    ((BowyerVoronoiVertex)f.Owner).RemoveNeighbour(f);
                }


                //Removing affected voronoi vertexes
                //Removing affected voronoi facets in nucleis
                foreach (var v in affectedVertexes)
                {
                    v.Dispose();
                }


                //Removing affected simplices
                voronoiVertexes.RemoveAll(v => v.IsTrash);

#if DEBUG
                if (secondaryAffecteVertexes.Any(f => f.FullyInitialized))
                {
                    throw new NotSupportedException("Incoherence in the problem");
                }
#endif
                affectedNucleis.Add(newNuclei);

                //--------------------- BUILDING NEW MESH --------------------------------------
                //build tesellation and check some neighbourhood with secondary
                var generatedVertexes = BuildTesellation(affectedNucleis, secondaryAffecteVertexes, nucleisRank);

                this.nucleis.Add(newNuclei);
                return(newNuclei.VoronoiHyperRegion);
            }
        }
        /// <summary>
        /// This function checks all requirements to build a tessellation, basically the number of independent nodes.
        /// If they are enough this method call to the buildTesellation method.
        /// </summary>        
        private bool TryBuildTesellation(INuclei[] PointsToRemake, List<ISimplice> oldSimplices)
        {
            //check enough points
            if (PointsToRemake.Length >= dimensions + 1)
            {
                //Candidate simplices will contain some old simplices
                //and some new maked up simplices
                IEnumerable<IEnumerable<INuclei>> candidateSimplicesNucleis = Helpers.Combinations(PointsToRemake, dimensions + 1);

                //the only thing we need is a combinatory function about the exploited points
                //generateCombinatorySimplicies(0,0, dimensions + 1, PointsToRemake, null, oldSimplices, candidateSimplices);

                List<ISimplice> candidateSimplices = new List<ISimplice>();

                foreach (var nucSet in candidateSimplicesNucleis)
                {
                    ISimplice existingSimplice = oldSimplices.FirstOrDefault(s => nucSet.All(n => s.Nucleis.Contains(n)));
                    if (existingSimplice != null)
                        candidateSimplices.Add(existingSimplice);
                    else
                    {
                        INuclei[] nucs = nucSet.ToArray();
                        if (Nuclei.AssertRank(nucs, dimensions))
                            candidateSimplices.Add(new Simplice(nucs));
                    }
                }

                //check enough independent points
                if (candidateSimplices.Any())
                {
                    BuildTesellationAndSetNeiborghood(candidateSimplices, PointsToRemake, oldSimplices);
                    return true;
                }
                else
                    return false; //not enough indepndent poitns to build a tessellation in this n-dimensional world
            }
            else
                return false; //not enough points to build a teselation in this n-dimensional world
        }
        private void BuildTesellationAndSetNeiborghood(List<ISimplice> candidateSimplices, INuclei[] pointsToRemake, List<ISimplice> oldSimplices)
        {
            List<Simplice> newTesellation = new List<Simplice>();
            foreach (Simplice s in candidateSimplices)
            {
                bool hyperSphereCoversPoint = false;
                foreach (var p in pointsToRemake.Except(s.Nucleis))
                {
                    if (s.CheckIsInsideCircumSphere(p.Coordinates))
                    {
                        hyperSphereCoversPoint = true;
                        break;
                    }
                }

                if (!hyperSphereCoversPoint)
                {
                    //if finally some new simplice existed previously
                    //they have not been exploited so don't mark them as new (recreate them)
                    //neither mark them to remove(oldSimplice) them because are stable and usefull simplices.

                    if (oldSimplices.Contains(s))
                        oldSimplices.Remove(s);
                    else
                        newTesellation.Add(s);

                }
            }

            /*var oldSimplices = newTesellation.Select(s => s.Nucleis as IEnumerable<Nuclei>)
                                            .Aggregate((acc, ns) => acc.Union(ns))
                                            .Distinct()
                                            .Select(n => n.simplices as IEnumerable<Simplice>)
                                            .Aggregate((acc, sim) => acc.Union(sim) )
                                            .Distinct()
                                            .Except(newTesellation)
                                            .ToArray();*/

            foreach (Simplice s in newTesellation)
            {
                foreach (Nuclei n in s.Nucleis)
                {

                    //Deleting refactored nuclei neighbourg for each nuclei.
                    //Assert that we do not remove any neighbour that is connected
                    //thorugh another simplice that won't be removed
                    foreach (Simplice os in oldSimplices.Where(x => x.Nucleis.Contains(n)))
                    {
                        n.simplices.Remove(os);
                        //remove neighbour not contained in other neighbourgs
                        var neighToRemove = os.Nucleis
                                          .Where(nuc => nuc != n &&
                                                        !n.simplices
                                                        .Any(sim => sim.Nucleis.Contains(nuc)));

                        foreach (var neighRm in neighToRemove)
                            n.nucleiNeigbourgs.Remove(neighRm);
                    }

                    if (n.simplices.Contains(s))
                        throw new Exception();

                    n.simplices.Add(s);
                    foreach (Nuclei newNeigbourg in s.Nucleis)
                        if (newNeigbourg != n && !n.nucleiNeigbourgs.Contains(newNeigbourg))
                        {
                            n.nucleiNeigbourgs.Add(newNeigbourg);
                        }
                }
                s.RaiseRefreshNeighbours();
            }

            foreach (Simplice s in oldSimplices)
            {
                s.RaiseRefreshNeighbours();
            }
        }
Beispiel #10
0
        private void CalculateConstraint()
        {
            //three possible cases, both finites, owner finite/external infnite and viceversa

            if (!Owner.Infinity && !external.Infinity)
            {
                double[] ownerPoint   = Owner.Coordinates;
                double[] foreignPoint = external.Coordinates;

                double[] coefficents = new Vector(ownerPoint.Length + 1);
                coefficents[coefficents.Length - 1] = 0;

                //calculating coefficents except the independent coefficent
                for (int i = 0; i < ownerPoint.Length; i++)
                {
                    coefficents[i] = ownerPoint[i] - foreignPoint[i];
                    //calculating the independent coefficent
                    coefficents[coefficents.Length - 1] -= coefficents[i] * ((foreignPoint[i] + ownerPoint[i]) / 2f);
                }
                this.constraint = new HyperPlaneConstraint(coefficents);
            }
            else if (External.Infinity && Owner.Infinity)
            {
                INuclei[] n = External.Simplice.Nucleis.Intersect(Owner.Simplice.Nucleis).ToArray();
                if (n.Length != 2)
                {
                    throw new NotSupportedException();
                }

                IVoronoiFacet vf          = n[0].VoronoiHyperRegion.Facets.Single(f => f.External == n[1]);
                double[]      coefficents = new Vector(Owner.Coordinates.Length + 1);
                for (int i = 0; i < Owner.Coordinates.Length; i++)
                {
                    coefficents[i] = vf[i];
                }
                this.constraint = new HyperPlaneConstraint(coefficents);
            }
            else if (External.Infinity)
            {
                if (Owner.Simplice.Nucleis.Length > 2)
                {
                    double[] middlePoint = new double[Nucleis[0].Coordinates.Length];
                    Helpers.CalculateSimpliceCentroidFromFacets(this.Nucleis, this.Rank, ref middlePoint);

                    Vector normal          = new Vector(Nucleis[0].Coordinates.Length + 1);
                    double independentTerm = 0;
                    for (int i = 0; i < Nucleis[0].Coordinates.Length; i++)
                    {
                        normal[i]        = Owner.Coordinates[i] - middlePoint[i];
                        independentTerm -= normal[i] * middlePoint[i];
                    }
                    normal[normal.Length - 1] = independentTerm;
                    this.constraint           = new HyperPlaneConstraint(normal.ToArray());
                }
                else
                {
                    //only two nucleis...is this enough general for n-dimensions?
                    //hope this is only the case base, where a voronoiVertex overlaps a voronoiFacet
                    INuclei n = External.Simplice.Nucleis.Intersect(Owner.Simplice.Nucleis).Single();

                    Vector normal          = new Vector(Nucleis[0].Coordinates.Length + 1);
                    double independentTerm = 0;
                    for (int i = 0; i < Nucleis[0].Coordinates.Length; i++)
                    {
                        normal[i]        = Owner.Coordinates[i] - n.Coordinates[i];
                        independentTerm -= normal[i] * n.Coordinates[i];
                    }
                    normal[normal.Length - 1] = independentTerm;
                    this.constraint           = new HyperPlaneConstraint(normal.ToArray());
                }
            }
            else if (Owner.Infinity)
            {
                if (External.Simplice.Nucleis.Length > 2)
                {
                    double[] middlePoint = new double[Nucleis[0].Coordinates.Length];
                    Helpers.CalculateSimpliceCentroidFromFacets(Nucleis, this.Rank, ref middlePoint);

                    Vector normal          = new Vector(Nucleis[0].Coordinates.Length + 1);
                    double independentTerm = 0;
                    for (int i = 0; i < Nucleis[0].Coordinates.Length; i++)
                    {
                        normal[i]        = middlePoint[i] - External.Coordinates[i];
                        independentTerm -= normal[i] * middlePoint[i];
                    }
                    normal[normal.Length - 1] = independentTerm;
                    this.constraint           = new HyperPlaneConstraint(normal.ToArray());
                }
                else
                {
                    //only two nucleis...is this enough general for n-dimensions?
                    //hope this is only the case base, where a voronoiVertex overlaps a voronoiFacet
                    INuclei n = External.Simplice.Nucleis.Intersect(Owner.Simplice.Nucleis).Single();

                    Vector normal          = new Vector(Nucleis[0].Coordinates.Length + 1);
                    double independentTerm = 0;
                    for (int i = 0; i < Nucleis[0].Coordinates.Length; i++)
                    {
                        normal[i]        = n.Coordinates[i] - External.Coordinates[i];
                        independentTerm -= normal[i] * n.Coordinates[i];
                    }
                    normal[normal.Length - 1] = independentTerm;
                    this.constraint           = new HyperPlaneConstraint(normal.ToArray());
                }
            }
            else //both infinities
            {
                throw new NotFiniteNumberException();
            }
        }
Beispiel #11
0
        /// <summary>
        /// This is a lazy calculation of the voronoi Vertex, its not calculated if it isn't required.
        /// </summary>
        internal static void CalculateSimpliceCentroidFromFacets(IEnumerable <INuclei> Nucleis, int simpliceDimensions, ref double[] vectorOut)
        {
            INuclei firstNuclei = Nucleis.First();


            int problemDimensionality = Nucleis.First().Coordinates.Length;

            IVoronoiFacet[] voronoiFacets = firstNuclei.VoronoiHyperRegion.Facets.Where(f => Nucleis.Contains(f.External)).ToArray();

            int Dof = problemDimensionality - simpliceDimensions;

            //we have facets.Length restrictions, and we have to create Dof new restrictions.
            if (simpliceDimensions == problemDimensionality)
            {
                CalculateSimpliceCentroid(Nucleis.Select(n => n.Coordinates), ref vectorOut);
            }
            else
            //we have to solve a facets.Length problem, to get the parameters of the problem.
            //ie: two facets, two ecuations. constraint with the current space formed by nucleiVectors with 2 parameters (unknowns)
            //this is a two ecuations/two unknowns problem.
            if (simpliceDimensions == 1)
            {
                IVoronoiFacet hpConstraint    = voronoiFacets[0];
                double        tCoeff          = 0;
                double        independentTerm = hpConstraint[problemDimensionality];
                Vector[]      vectors         = VectorsFromPoints(Nucleis, simpliceDimensions + 1);
                for (int i = 0; i < problemDimensionality; i++)
                {
                    tCoeff          += hpConstraint[i] * vectors[0][i];
                    independentTerm += hpConstraint[i] * firstNuclei.Coordinates[i];
                }
                double t = (-independentTerm) / tCoeff;

                //solve the system
                for (int i = 0; i < problemDimensionality; i++)
                {
                    vectorOut[i] = firstNuclei.Coordinates[i] + t * vectors[0][i];
                }
            }
            else
            {
                //parameters matrix
                Matrix   mA      = new Matrix(voronoiFacets.Length, voronoiFacets.Length);
                Vector[] vectors = VectorsFromPoints(Nucleis, simpliceDimensions + 1);
                Matrix   mb      = new Matrix(voronoiFacets.Length, 1);

                //mounting parameters matrix
                for (int row = 0; row < voronoiFacets.Length; row++)
                {
                    IVoronoiFacet hpConstraint    = voronoiFacets[row];
                    double        independentTerm = hpConstraint[problemDimensionality];
                    for (int col = 0; col < voronoiFacets.Length; col++)
                    {
                        double tCoeff_col = 0;
                        for (int j = 0; j < problemDimensionality; j++)
                        {
                            tCoeff_col      += hpConstraint[j] * vectors[col][j];
                            independentTerm += hpConstraint[j] * firstNuclei.Coordinates[j];
                        }
                        mA[row, col] = tCoeff_col;
                    }
                    mb[row, 0] = independentTerm;
                }

                //solving parameters matrix
                Matrix parametersRes = mA.Solve(mb);
                for (int i = 0; i < vectorOut.Length; i++)
                {
                    double increment = 0;
                    for (int j = 0; j < voronoiFacets.Length; j++)
                    {
                        increment = parametersRes[j, 0] * vectors[j][i];
                    }

                    vectorOut[i] = firstNuclei.Coordinates[i] + increment;
                }
            }
        }
 /// <summary>
 /// The number of nodes must be n+1 dimensional where n is the dimensions of the problem
 /// </summary>
 /// <param name="nucleis"></param>
 public Simplice(INuclei[] nucleis)
 {
     this.Nucleis = nucleis;
 }
        internal static bool AssertRank(INuclei[] nucleis, int desiredRank)
        {
            if (nucleis.Length < desiredRank)
                return false;

            int workingSpaceDim=nucleis.First().Coordinates.Length;
            Matrix m = new Matrix(nucleis.Length,workingSpaceDim );
            for(int i=0;i<nucleis.Length;i++)
            {
                for(int j=0;j<workingSpaceDim;j++)
                    m[i,j]=nucleis[i].Coordinates[j];
            }

            return m.Rank()==desiredRank;
        }
        public IVoronoiRegion AddNewPoint(object data, double[] newPoint)
        {
            if (newPoint == null || newPoint.Length != ProblemDimensionality)
                throw new ArgumentException("point added null or has invalid dimensionality");

            BowyerNuclei newNuclei = new BowyerNuclei(newPoint);
            newNuclei.Data = data;

            //SPECIAL CASE FOR FIRST ADD
            if (!voronoiVertexes.Any())
            {
                //no voronoiVertexes
                //no simplices
                //no regions

                BowyerNuclei[] nucleis = new BowyerNuclei[1];
                newNuclei = nucleis[0] = new BowyerNuclei(newPoint);
                newNuclei.Data = data;

                //create a VoronoiVertex in the infinite
                var voronoiVertex = new BowyerVoronoiVertex(0, nucleis, new HyperSphereConstraint(newNuclei.Coordinates, double.PositiveInfinity));

                this.voronoiVertexes.Add(voronoiVertex);
                this.nucleis.Add(newNuclei);

                //create a not formed Simplice
                return voronoiVertexes.First().Simplice.Nucleis.First().VoronoiHyperRegion;
            }
            else
            {

                //--------------- SITUATION ANALYSIS - READ ONLY--------------

#warning optimizable: not variable list without cast, external auxiliar attribute
                List<BowyerVoronoiVertex> affectedVertexes = new List<BowyerVoronoiVertex>();
#warning optimizable: not variable list without cast, external auxiliar attribute
                List<BowyerNuclei> affectedNucleis = new List<BowyerNuclei>();


                IEnumerable<INuclei> newpointSet = new INuclei[] { newNuclei };

#warning optimizable: cant be this an auxiliar attribute?
                var secondaryAffecteVertexes = new List<BowyerSimpliceFacet>();


                if (nucleisRank < ProblemDimensionality && Helpers.CalculatePointsRank(Simplices.First().Nucleis.Union(newpointSet)) > nucleisRank)
                {
                    affectedVertexes = this.voronoiVertexes;
                    nucleisRank++;
                    foreach (var v in affectedVertexes)
                        v.IsTrash = true;

#warning optimize, eliminate the cast and create a nuclei List
                    affectedNucleis.AddRange(this.Nucleis.Cast<BowyerNuclei>());
                }
                else
                {
                    IVoronoiRegion r = GetMatchingRegion(newPoint);
                    // and use r.Vertexes
                    foreach (BowyerVoronoiVertex v in r.Vertexes)
                        if (v.Simplice.CircumsphereContains(newPoint))
                        {
                            if (!affectedVertexes.Contains(v))
                            {
                                affectedVertexes.Add(v);
                                v.IsTrash = true;
                                foreach (var affectedNuclei in v.simplice.nucleis)
                                    if (!affectedNucleis.Contains(affectedNuclei))
                                        affectedNucleis.Add(affectedNuclei);
                            }

                            foreach (var vaffected in v.simplice.facets.Where(f => f.External.Infinity).Select(f => (BowyerVoronoiVertex)f.External))
                            {
                                if (!affectedVertexes.Contains(vaffected))
                                {
                                    affectedVertexes.Add(vaffected);
                                    vaffected.IsTrash = true;
                                }

                            }

                            foreach (var otherAffectedFace in v.simplice.facets.Where(f => !f.External.Infinity))
                            {
                                if (!affectedVertexes.Contains((BowyerVoronoiVertex)otherAffectedFace.External) && !secondaryAffecteVertexes.Contains(otherAffectedFace))
                                    secondaryAffecteVertexes.Add(otherAffectedFace);
                            }


                            //add also all the infinite vertexes if it or neighbours who contains it
                            //foreach (var vneigh2 in v.simplice.facets
                            //                                      .Where(f => !affectedVertexes.Contains((BowyerVoronoiVertex)f.External)
                            //                                                  && (f.External.Infinity
                            //                                                     || f.External.Simplice.CircumsphereContains(newPoint)))
                            //                                      .Select(f => (BowyerVoronoiVertex)f.External))
                            //{
                            //    vneigh2.IsTrash = true;
                            //    affectedVertexes.Add(vneigh2);

                            //}
                        }
                }



                //if (!affectedVertexes.Any())
                //{
                //    //if no normal simplices contains the new point
                //    //we will to try it in infinite vertexs of this region
                //    foreach (BowyerVoronoiVertex v in r.Vertexes.Where(v => v.Infinity))
                //        if (v.Simplice.CircumsphereContains(newPoint))
                //        {
                //            affectedVertexes.Add(v);
                //            v.IsTrash = true;
                //            affectedNucleis.AddRange(v.simplice.nucleis);

                //            //add to affected vertexes also the only neighbour vertex of
                //            //the current infinite vertex
                //            BowyerVoronoiVertex vnormal = (BowyerVoronoiVertex)v.simplice.facets.Single().External;
                //            secondaryAffecteVertexes.Add(vnormal);

                //            //vnormal.IsTrash = true;
                //            //affectedVertexes.Add(vnormal);
                //            ////add also all the infinite vertexes if it or neighbours who contains it
                //            //foreach (var vneigh2 in vnormal.simplice.facets.Select(f => (BowyerVoronoiVertex)f.External)
                //            //                                               .Where(v2 => v2 != v && !affectedVertexes.Contains(v2)
                //            //                                                   && (v2.Infinity || v2.simplice.CircumsphereContains(newPoint))))
                //            //{
                //            //    vneigh2.IsTrash = true;
                //            //    affectedVertexes.Add(vneigh2);
                //            //}

                //      }
                //  }

                // }

#if DEBUG
                Debug.Print(string.Format("{0} ||| adding new point. Affected vertexes: {1}. Secondary Affected vertexes: {2}", this.ToString(), affectedVertexes.Count, secondaryAffecteVertexes.Count));

                if (!affectedVertexes.Any())
                    throw new ArgumentException("this case is not possible and has not been contemplated");

                if (affectedVertexes.Distinct().Count() != affectedVertexes.Count)
                    throw new ArgumentException("Incoherence in the algorithm");

                if (affectedNucleis.Distinct().Count() != affectedNucleis.Count)
                    throw new ArgumentException("Incoherence in the algorithm");

                if (secondaryAffecteVertexes.Distinct().Count() != secondaryAffecteVertexes.Count)
                    throw new ArgumentException("Incoherence in the algorithm");

#endif


                //if any candidate vertex sismplice has the maxium dimensionality, the postgenerated tesellation will also have this maxium dimensionality

                //if (affectedVertexes.First().Simplice.Dimensionality == ProblemDimensionality)
                //    nucleisRank = ProblemDimensionality;
                //else
                //    nucleisRank = Helpers.CalculatePointsRank(affectedNucleisArray);



                //--------------------- CLEARING EXISTING DATA -------------------------------------- 

                foreach (var f in secondaryAffecteVertexes)
                    ((BowyerVoronoiVertex)f.Owner).RemoveNeighbour(f);


                //Removing affected voronoi vertexes
                //Removing affected voronoi facets in nucleis
                foreach (var v in affectedVertexes)
                    v.Dispose();


                //Removing affected simplices
                voronoiVertexes.RemoveAll(v => v.IsTrash);

#if DEBUG
                if (secondaryAffecteVertexes.Any(f => f.FullyInitialized))
                    throw new NotSupportedException("Incoherence in the problem");
#endif
                affectedNucleis.Add(newNuclei);

                //--------------------- BUILDING NEW MESH -------------------------------------- 
                //build tesellation and check some neighbourhood with secondary
                var generatedVertexes = BuildTesellation(affectedNucleis, secondaryAffecteVertexes, nucleisRank);

                this.nucleis.Add(newNuclei);
                return newNuclei.VoronoiHyperRegion;

            }
        }
        public IEnumerable<ISimpliceFacet> GetFacetOrNull(INuclei n1, INuclei n2)
        {
            IEnumerable<BowyerSimplice> intersectionSimplices=((BowyerNuclei)n1).simplices.Where(s => s.nucleis.Contains(n2));
            var facetsA=intersectionSimplices.Select(s => s.Facets.SingleOrDefault(f => f.Nucleis.Contains(n2) && f.Nucleis.Contains(n1)))
                                              .Where(f=>f!=null);

            return facetsA;

        }