Esempio n. 1
0
        static Vector ComputeIntersection(Vector S, Vector E, AffineManifold clipEdge)
        {
            var SE = AffineManifold.FromPoints(S, E);
            var I  = AffineManifold.Intersect2D(SE, clipEdge);

            //var D = S - E;
            //D.Normalize();
            //var N1 = new Vector(D.y, -D.x);
            //double inner = N1 * clipEdge.Normal;

            Debug.Assert(!double.IsNaN(I.x));
            Debug.Assert(!double.IsInfinity(I.x));
            Debug.Assert(!double.IsNaN(I.y));
            Debug.Assert(!double.IsInfinity(I.y));

            return(I);
        }
Esempio n. 2
0
        /// <summary>
        /// Intersection of line <paramref name="S1"/>--<paramref name="S2"/> and <paramref name="E1"/>--<paramref name="E2"/>
        /// </summary>
        /// <param name="S1"></param>
        /// <param name="S2"></param>
        /// <param name="E1"></param>
        /// <param name="E2"></param>
        /// <param name="alpha1">
        /// coordinate of <paramref name="I"/> on the line <paramref name="S1"/>--<paramref name="S2"/>
        /// </param>
        /// <param name="alpha2">
        /// coordinate of <paramref name="I"/> on the line <paramref name="E1"/>--<paramref name="E2"/>
        /// </param>
        /// <param name="I"></param>
        /// <returns></returns>
        public static bool ComputeIntersection(Vector S1, Vector S2, Vector E1, Vector E2, out double alpha1, out double alpha2, out Vector I)
        {
            if (S1.Dim != 2)
            {
                throw new ArgumentException("spatial dimension mismatch.");
            }
            if (S2.Dim != 2)
            {
                throw new ArgumentException("spatial dimension mismatch.");
            }
            if (E1.Dim != 2)
            {
                throw new ArgumentException("spatial dimension mismatch.");
            }
            if (E2.Dim != 2)
            {
                throw new ArgumentException("spatial dimension mismatch.");
            }

            Vector S12 = S2 - S1;
            Vector E12 = E2 - E1;

            var P_S12 = AffineManifold.FromPoints(S1, S2);
            var P_E12 = AffineManifold.FromPoints(E1, E2);

            double parallel    = S12[0] * E12[1] - S12[1] * E12[0];
            double relParallel = parallel * parallel / (S12.AbsSquare() * E12.AbsSquare());

            if (Math.Abs(relParallel) <= 1e-20)
            {
                alpha1  = P_S12.PointDistance(E1);
                alpha1 /= E12.Abs();
                alpha2  = double.PositiveInfinity;
                I       = new Vector(double.PositiveInfinity, double.PositiveInfinity);
                return(false);
            }

            //S12.Normalize();
            //E12.Normalize();

            I = AffineManifold.Intersect2D(P_S12, P_E12);

            Vector IS1 = I - S2;
            Vector IE1 = I - E2;
            Vector IS2 = I - S1;
            Vector IE2 = I - E1;

            Vector IS;
            bool   flip_1;

            if (IS1.AbsSquare() > IS2.AbsSquare())
            {
                IS     = IS1;
                flip_1 = true;
            }
            else
            {
                IS     = IS2;
                flip_1 = false;
            }

            Vector IE;
            bool   flip_2;

            if (IE1.AbsSquare() > IE2.AbsSquare())
            {
                IE     = IE1;
                flip_2 = true;
            }
            else
            {
                IE     = IE2;
                flip_2 = false;
            }

            Debug.Assert((S12.AngleTo(IS).Abs() <= 1.0e-5) || ((S12.AngleTo(IS).Abs() - Math.PI).Abs() <= 1.0e-5));
            Debug.Assert((E12.AngleTo(IE).Abs() <= 1.0e-5) || ((E12.AngleTo(IE).Abs() - Math.PI).Abs() <= 1.0e-5));

            alpha1 = (S12 * IS) / S12.AbsSquare();
            alpha2 = (E12 * IE) / E12.AbsSquare();

            if (flip_1)
            {
                alpha1 = 1 + alpha1;
            }
            if (flip_2)
            {
                alpha2 = 1 + alpha2;
            }

            return(true);
        }
Esempio n. 3
0
        public void CreateWithMatlab()
        {
            // ================================
            // generate voronoi graph in matlab
            // ================================


            int J = this.DelaunayVertices.NoOfRows;
            int D = this.DelaunayVertices.NoOfCols;

            if (D != 2)
            {
                throw new NotSupportedException("todo");
            }


            int[][] OutputVertexIndex = new int[J * 5][];
            MultidimensionalArray VertexCoordinates;
            {
                var Matlab = new BatchmodeConnector();

                Matlab.PutMatrix(this.DelaunayVertices, "X");

                // create mirror points
                Matlab.Cmd("[J, D] = size(X);");
                Matlab.Cmd("Xneg = [-X(:, 1), X(:, 2)];");
                Matlab.Cmd("Yneg = [X(:, 1), -X(:, 2)];");
                Matlab.Cmd("X2 = [ones(J, 1) * 2, zeros(J, 1)];");
                Matlab.Cmd("Y2 = [zeros(J, 1), ones(J, 1) * 2];");

                Matlab.Cmd("Xm = X;");
                Matlab.Cmd("Xm = [Xm; Xneg];    % mirror at x = 0");
                Matlab.Cmd("Xm = [Xm; X2 + Xneg]; % mirror at x = 1");
                Matlab.Cmd("Xm = [Xm; Yneg];    % mirror at x = 0");
                Matlab.Cmd("Xm = [Xm; Y2 + Yneg]; % mirror at x = 1");

                // compute Voronoi diagramm
                Matlab.Cmd("[V, C] = voronoin(Xm);");

                // output (export from matlab)
                Matlab.GetStaggeredIntArray(OutputVertexIndex, "C");
                Matlab.GetMatrix(null, "V");

                // run matlab
                Matlab.Execute(false);

                // import here
                VertexCoordinates = (MultidimensionalArray)(Matlab.OutputObjects["V"]);

                // correct indices (1-based index to 0-based index)
                foreach (int[] cell in OutputVertexIndex)
                {
                    int K = cell.Length;
                    for (int k = 0; k < K; k++)
                    {
                        cell[k]--;
                    }
                }
            }

            // ===============
            // record internal
            // ===============

            {
                // define Cell data
                {
                    this.m_CellData         = new CellData();
                    this.m_CellData.m_Owner = this;
                    this.m_VertexData       = new VertexData();
                    this.m_LogEdges         = new LogEdgeData();

                    this.m_VertexData.Coordinates = VertexCoordinates;
                    this.m_CellData.CellVertices  = OutputVertexIndex.GetSubVector(0, J);

                    this.m_CellData.InfoFlags = new CellInfo[J];
                    ArrayTools.SetAll(this.m_CellData.InfoFlags, CellInfo.CellIsAffineLinear | CellInfo.IsAggregate);
                }

                // decomposition of Voronoi cells to triangles/tetrahedrons
                {
                    m_CellData.AggregateCellToParts = new int[J][];
                    if (D == 2)
                    {
                        var Tri = RefElements.Triangle.Instance;
                        m_CellData.RefElements = new RefElement[] { Tri };

                        int cnt = 0;
                        for (int j = 0; j < J; j++)
                        {
                            int[] VtxIndices = m_CellData.CellVertices[j];

                            int[] PartIdx = new int[VtxIndices.Length - 2];
                            for (int i = 0; i < PartIdx.Length; i++)
                            {
                                PartIdx[i] = cnt;
                                cnt++;
                            }
                            m_CellData.AggregateCellToParts[j] = PartIdx;
                        }

                        int NoOfParts = cnt;
                        m_CellData.PartTransformation = MultidimensionalArray.Create(NoOfParts, D, D);
                        m_CellData.PartCenter         = MultidimensionalArray.Create(NoOfParts, D);

                        MultidimensionalArray TriangleVtx = MultidimensionalArray.Create(3, D);
                        for (int j = 0; j < J; j++)
                        {
                            int[] VtxIndices = m_CellData.CellVertices[j];
                            int[] PartIdx    = m_CellData.AggregateCellToParts[j];

                            for (int i = 0; i < PartIdx.Length; i++)
                            {
                                int iV0 = VtxIndices[0];
                                int iV1 = VtxIndices[i + 1];
                                int iV2 = VtxIndices[i + 2];

                                TriangleVtx[0, 0] = m_VertexData.Coordinates[iV0, 0];
                                TriangleVtx[0, 1] = m_VertexData.Coordinates[iV0, 1];
                                TriangleVtx[1, 0] = m_VertexData.Coordinates[iV1, 0];
                                TriangleVtx[1, 1] = m_VertexData.Coordinates[iV1, 1];
                                TriangleVtx[2, 0] = m_VertexData.Coordinates[iV2, 0];
                                TriangleVtx[2, 1] = m_VertexData.Coordinates[iV2, 1];

                                var TR = AffineTrafo.FromPoints(Tri.Vertices, TriangleVtx);

                                m_CellData.PartTransformation.ExtractSubArrayShallow(PartIdx[i], -1, -1).Set(TR.Matrix);
                                m_CellData.PartCenter.ExtractSubArrayShallow(PartIdx[i], -1).SetVector(TR.Affine);
                            }
                        }
                    }
                    else if (D == 3)
                    {
                        throw new NotImplementedException("todo");
                    }
                    else
                    {
                        throw new NotSupportedException("Unknown spatial dimension.");
                    }
                }

                // bounding boxes, transformations
                {
                    BoundingBox BB = new BoundingBox(D);
                    m_CellData.BoundingBoxTransformation = MultidimensionalArray.Create(J, D, D);
                    m_CellData.BoundingBoxCenter         = MultidimensionalArray.Create(J, D);
                    for (int j = 0; j < J; j++)
                    {
                        m_CellData.GetCellBoundingBox(j, BB);
                        for (int d = 0; d < D; d++)
                        {
                            double lo = BB.Min[d];
                            double hi = BB.Max[d];
                            m_CellData.BoundingBoxCenter[j, d]            = 0.5 * (lo + hi);
                            m_CellData.BoundingBoxTransformation[j, d, d] = 0.5 * (hi - lo);
                        }
                    }
                }

                // mapping: vertex to cell
                {
                    List <int>[] VertexToCell = new List <int> [VertexCoordinates.Length];
                    for (int j = 0; j < J; j++)
                    {
                        foreach (int iVtx in OutputVertexIndex[j])
                        {
                            if (VertexToCell[iVtx] == null)
                            {
                                VertexToCell[iVtx] = new List <int>();
                            }

                            if (!VertexToCell[iVtx].Contains(j))
                            {
                                VertexToCell[iVtx].Add(j);
                            }
                        }
                    }

                    m_VertexData.VerticeToCell = new int[VertexToCell.Length][];
                    for (int i = 0; i < VertexToCell.Length; i++)
                    {
                        if (VertexToCell[i] == null)
                        {
                            m_VertexData.VerticeToCell[i] = new int[0];
                        }
                        else
                        {
                            m_VertexData.VerticeToCell[i] = VertexToCell[i].ToArray();
                        }
                    }
                    VertexToCell = null;
                }

                // cell neighbors, edges
                {
                    m_CellData.CellNeighbours = new int[J][];
                    var tmpCells2Edges = new List <int> [J];

                    Dictionary <int, int> ShareCount = new Dictionary <int, int>(); // key: cell index; value: number of vertices shared with this cell
                    var        EdgesTemp             = new List <EdgeTemp>();
                    List <int> Neighs            = new List <int>();
                    List <int> EdgeVtx           = new List <int>();
                    List <int> IdedEdgsAtOneCell = new List <int>();
                    for (int jCell = 0; jCell < J; jCell++)   // loop over cells
                    {
                        ShareCount.Clear();
                        Neighs.Clear();
                        IdedEdgsAtOneCell.Clear();

                        // determine how many vertices 'jCell' shares with other cells
                        foreach (int iVtx in m_CellData.CellVertices[jCell])
                        {
                            foreach (int jOtherCell in m_VertexData.VerticeToCell[iVtx])
                            {
                                if (jOtherCell != jCell)
                                {
                                    if (!ShareCount.ContainsKey(jOtherCell))
                                    {
                                        ShareCount.Add(jOtherCell, 1);
                                    }
                                    else
                                    {
                                        ShareCount[jOtherCell]++;
                                    }
                                }
                            }
                        }

                        // find faces
                        int[][] FaceIdx = ConvexHullFaces(m_VertexData.Coordinates, m_CellData.CellVertices[jCell]);

                        // determine cell neighbors and edges
                        int NoOfFacesFound = 0;
                        foreach (var kv in ShareCount)
                        {
                            int jCellNeigh    = kv.Key;
                            int NoOfSharedVtx = kv.Value;
                            if (NoOfSharedVtx >= D)
                            {
                                // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                // cells 'jCell' and 'jCellNeigh' share more than 'D' vertices - this is an edge to another cell,
                                // resp. a face of 'jCell'.
                                // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

                                Debug.Assert(jCellNeigh != jCell);
                                Debug.Assert(!Neighs.Contains(jCellNeigh));
                                Neighs.Add(jCellNeigh);
                                NoOfFacesFound++;

                                EdgeVtx.Clear();
                                foreach (int iVtx in m_CellData.CellVertices[jCell])
                                {
                                    if (Array.IndexOf(m_VertexData.VerticeToCell[iVtx], jCellNeigh) >= 0)
                                    {
                                        EdgeVtx.Add(iVtx);
                                    }
                                }


                                if (jCell < jCellNeigh)
                                {
                                    // the pairing 'jCell'/'jCellNeigh' will be discovered twice;
                                    // we only want to record once

                                    var Etmp = new EdgeTemp()
                                    {
                                        jCell1   = jCell,
                                        jCell2   = jCellNeigh,
                                        Vertices = EdgeVtx.ToArray()
                                    };
                                    EdgesTemp.Add(Etmp);
                                    IdedEdgsAtOneCell.Add(EdgesTemp.Count - 1);
                                    if (tmpCells2Edges[jCell] == null)
                                    {
                                        tmpCells2Edges[jCell] = new List <int>();
                                    }
                                    if (tmpCells2Edges[jCellNeigh] == null)
                                    {
                                        tmpCells2Edges[jCellNeigh] = new List <int>();
                                    }
                                    tmpCells2Edges[jCell].Add(EdgesTemp.Count);       // the funky convention for edges-to-cell: the index is
                                    tmpCells2Edges[jCellNeigh].Add(-EdgesTemp.Count); // shifted by 1, out-cell is negative
                                }
                                else
                                {
                                    Debug.Assert(jCellNeigh < jCell);

                                    int MatchCount = 0;
                                    foreach (int i in tmpCells2Edges[jCellNeigh])
                                    {
                                        int iEdge = Math.Abs(i) - 1;

                                        if (EdgesTemp[iEdge].jCell1 == jCellNeigh && EdgesTemp[iEdge].jCell2 == jCell)
                                        {
                                            MatchCount++;
                                            IdedEdgsAtOneCell.Add(iEdge);
                                        }
                                    }
                                    Debug.Assert(MatchCount == 1);
                                }
#if DEBUG
                                if (D == 2)
                                {
                                    Debug.Assert(EdgeVtx.Count == 2);
                                }
                                else if (D == 3)
                                {
                                    // verify that all vertices of the edge are geometrically in one plane

                                    Debug.Assert(EdgeVtx.Count >= 3);
                                    var FacePlane = AffineManifold.FromPoints(
                                        m_VertexData.Coordinates.GetRowPt(EdgeVtx[0]),
                                        m_VertexData.Coordinates.GetRowPt(EdgeVtx[1]),
                                        m_VertexData.Coordinates.GetRowPt(EdgeVtx[2])
                                        );

                                    BoundingBox BB = new BoundingBox(D);
                                    m_CellData.GetCellBoundingBox(jCell, BB);
                                    double h = BB.Diameter;

                                    foreach (int iVtx in EdgeVtx)
                                    {
                                        double dist = Math.Abs(FacePlane.PointDistance(m_VertexData.Coordinates.GetRow(iVtx)));
                                        Debug.Assert(dist < h * 1e-8);
                                    }
                                }
                                else
                                {
                                    throw new NotSupportedException("Unknown spatial dimension.");
                                }
#endif
                            }
                        }
                        m_CellData.CellNeighbours[jCell] = Neighs.ToArray();
                        Debug.Assert(NoOfFacesFound <= FaceIdx.Length);
                        Debug.Assert(NoOfFacesFound == IdedEdgsAtOneCell.Count);

                        // boundary edges
                        if (NoOfFacesFound == FaceIdx.Length)
                        {
                            // nothing to do - all faces/edges identified
#if DEBUG
                            for (int i = 0; i < NoOfFacesFound; i++)
                            {
                                int Matches = 0;
                                for (int l = 0; l < NoOfFacesFound; l++)
                                {
                                    if (FaceIdx[i].SetEquals(EdgesTemp[IdedEdgsAtOneCell[l]].Vertices))
                                    {
                                        Matches++;
                                    }
                                }
                                Debug.Assert(Matches == 1);
                            }
#endif
                        }
                        else
                        {
                            // missing boundary

                            for (int i = 0; i < FaceIdx.Length; i++)
                            {
                                int Matches = 0;
                                for (int l = 0; l < NoOfFacesFound; l++)
                                {
                                    if (FaceIdx[i].SetEquals(EdgesTemp[IdedEdgsAtOneCell[l]].Vertices))
                                    {
                                        Matches++;
                                    }
                                }
                                Debug.Assert(Matches <= 1);

                                if (Matches == 0)
                                {
                                    // boundary edge found
                                    var Etmp = new EdgeTemp()
                                    {
                                        jCell1   = jCell,
                                        jCell2   = int.MinValue,
                                        Vertices = EdgeVtx.ToArray()
                                    };
                                    EdgesTemp.Add(Etmp);
                                    tmpCells2Edges[jCell].Add(EdgesTemp.Count); // index shifted by 1
                                }
                            }
                        }
                    }

                    // convert temporary data structures to the final ones
                    m_CellData.Cells2Edges = new int[J][];
                    var C2E = m_CellData.Cells2Edges;
                    for (int j = 0; j < J; j++)
                    {
                        C2E[j] = tmpCells2Edges[j] != null ? tmpCells2Edges[j].ToArray() : new int[0];
                    }


                    m_GeomEdges = new GeomEdgeData();
                    int NoOfEdges = EdgesTemp.Count;
                    m_GeomEdges.Info          = new EdgeInfo[NoOfEdges];
                    m_LogEdges.CellIndices    = new int[NoOfEdges, 2];
                    m_GeomEdges.VertexIndices = new int[NoOfEdges][];
                    var Evtx = m_GeomEdges.VertexIndices;
                    var E2C  = m_LogEdges.CellIndices;
                    var Einf = m_GeomEdges.Info;
                    for (int iEdge = 0; iEdge < NoOfEdges; iEdge++)
                    {
                        var Etmp = EdgesTemp[iEdge];
                        E2C[iEdge, 0] = Etmp.jCell1;
                        E2C[iEdge, 1] = Etmp.jCell2;
                        Einf[iEdge]   = EdgeInfo.EdgeIsAffineLinear | EdgeInfo.IsAggregate;
                        if (Etmp.jCell2 < 0)
                        {
                            Einf[iEdge] |= EdgeInfo.Boundary;
                        }
                        Evtx[iEdge] = Etmp.Vertices;
                    }
                }


                // edge metrics
                {
                    if (D == 2)
                    {
                        m_GeomEdges.EdgeRefElements = new RefElement[] { Line.Instance };
                    }
                    else if (D == 3)
                    {
                        m_GeomEdges.EdgeRefElements = new RefElement[] { Triangle.Instance };
                    }
                    else
                    {
                        throw new NotSupportedException("Unknown spatial dimension.");
                    }

                    int[][] Evtx = m_GeomEdges.VertexIndices;

                    int NoOfParts = 0;
                    int NoOfEdges = m_GeomEdges.Count;
                    for (int iEdge = 0; iEdge < NoOfEdges; iEdge++)
                    {
                        NoOfParts += Evtx[iEdge].Length - D + 1;
                    }
                    Debug.Assert(D != 2 || NoOfParts == NoOfEdges);

                    m_GeomEdges.Edge2CellTrafoIndex = new int[NoOfParts, 2];
                    var tmpEdg2CellTrafo = new Dictionary <int, Tuple <int, AffineTrafo> >();

                    // unsolved problem:
                    // (D-1) -- dimensional tesselation of edge is given by D -- dimensional tesselation of adjacent cells
                    // * case D == 2: trivial
                    // * case D == 3: the problem is that two adjacent cells will induce _two different_ tesselations, which
                    //                wont match in the general case.


                    MultidimensionalArray PreImage = m_GeomEdges.EdgeRefElements[0].Vertices;
                    MultidimensionalArray Image    = MultidimensionalArray.Create(PreImage.NoOfRows, D);

                    //for(int iEdge )
                }
            }
        }