void k_closest_points(KInt2 Xq, int cnt, List <int> idxs)
        {
            // initialize search data
            Bmin = KInt2.min;
            Bmax = KInt2.max;

            this.k = cnt;

            // call search on the root [0] fill the queue
            // with elements from the search
            knn_search(Xq);

            // scan the created pq and extract the first "k" elements
            // pop the remaining
            int N = pq.size();

            for (int i = 0; i < N; i++)
            {
                ClsTuple <float, int> topel = pq.top();
                pq.pop();
                if (i >= N - k)
                {
                    idxs.Add(topel.Value);
                }
            }

            // invert the vector, passing first closest results
            idxs.Reverse();
        }
        /** @see ball_query, range_query
         *
         * Returns all the points withing the ball bounding box and their distances
         *
         * @note this is similar to "range_query" i just replaced "lies_in_range" with "euclidean_distance"
         */
        void ball_bbox_query(int nodeIdx, KInt2 pmin, KInt2 pmax, List <int> inrange_idxs, List <float> distances, KInt2 point, float radiusSquared, int dim = 0)
        {
            GameKdTreeNode node = nodesPtrs[nodeIdx];

            // if it's a leaf and it lies in R
            if (node.isLeaf())
            {
                float distance = (points[node.pIdx] - point).sqrMagnitude;
                if (distance <= radiusSquared)
                {
                    inrange_idxs.Add(node.pIdx);
                    if (distances != null)
                    {
                        distances.Add(distance);
                    }
                    return;
                }
            }
            else
            {
                if (node.key >= pmin[dim] && node.LIdx != -1)
                {
                    ball_bbox_query(node.LIdx, pmin, pmax, inrange_idxs, distances, point, radiusSquared, (dim + 1) % ndim);
                }
                if (node.key <= pmax[dim] && node.RIdx != -1)
                {
                    ball_bbox_query(node.RIdx, pmin, pmax, inrange_idxs, distances, point, radiusSquared, (dim + 1) % ndim);
                }
            }
        }
Exemple #3
0
 public bool Equals(KInt2 first, KInt2 second)
 {
     if ((start == first && end == second) || (end == first && start == second))
     {
         return(true);
     }
     return(false);
 }
Exemple #4
0
 private static bool InRange(KInt2 p1, KInt2 k1, KInt2 k2)
 {
     if (((p1.IntX >= k1.IntX && p1.IntX <= k2.IntX) || (p1.IntX >= k2.IntX && p1.IntX <= k1.IntX)) &&
         ((p1.IntY >= k1.IntY && p1.IntY <= k2.IntY) || (p1.IntY >= k2.IntY && p1.IntY <= k1.IntY)))
     {
         return(true);
     }
     return(false);
 }
Exemple #5
0
        public bool ContainsSegment(Segment segment)
        {
            KInt2 selfdir  = this.direction;
            KInt2 otherdir = segment.direction;

            if (selfdir == otherdir || selfdir == -otherdir)
            {
                return(InRange(segment.start, this.start, this.end) && InRange(segment.end, this.start, this.end));
            }
            return(false);
        }
 public void ball_query(KInt2 point, float radius, List <int> idxsInRange, List <float> distances)
 {
     if (nodesPtrs.Count > 0)
     {
         // create pmin pmax that bound the sphere
         KInt2 pmin = new KInt2(point.x - radius, point.y - radius);
         KInt2 pmax = new KInt2(point.x + radius, point.y + radius);
         // start from root at zero-th dimension
         ball_bbox_query(0, pmin, pmax, idxsInRange, distances, point, radius * radius, 0);
     }
 }
Exemple #7
0
        public Segment(KInt2 first, KInt2 second, int id)
        {
            this.start = first;
            this.end   = second;
            cachedir   = null;
            uid        = id;

            this.MinX = KMath.Min(this.start.IntX, this.end.IntX);
            this.MaxX = KMath.Max(this.start.IntX, this.end.IntX);
            this.MinY = KMath.Min(this.start.IntY, this.end.IntY);
            this.MaxY = KMath.Max(this.start.IntY, this.end.IntY);
        }
Exemple #8
0
 void AddtoList(HashSet <Segment> container, List <KInt2> linequeue)
 {
     if (linequeue.Count > 2)
     {
         container.Add(new Segment(linequeue [0], linequeue [1]));
         for (int i = 1; i < linequeue.Count - 1; ++i)
         {
             KInt2 current = linequeue [i];
             KInt2 next    = linequeue [i + 1];
             container.Add(new Segment(current, next));
         }
     }
 }
Exemple #9
0
        public static bool isConnectRetPoints(KInt2 selfstart, KInt2 selfend, KInt2 otherstart, KInt2 otherend, out KInt2 p1, out KInt2 p2, out KInt2 p3)
        {
            p1 = selfstart;
            p2 = selfend;
            p3 = selfstart;

            bool b1 = selfstart == otherstart;
            bool b2 = selfend == otherend;

            bool  b3      = selfstart == otherend;
            bool  b4      = selfend == otherstart;
            KInt2 dir     = (otherend - otherstart).normalized;
            KInt2 selfdir = (selfend - selfstart).normalized;

            if ((b1 && b2) || (b3 && b4))
            {
                return(false);
            }
            else if (b1 || b2)
            {
                p1 = b1 ? selfstart:selfend;
                p2 = b1 ? selfend :selfstart;
                p3 = b1 ? otherend:otherstart;

                if (selfdir == dir)
                {
                    return(false);
                }
                return(true);
            }
            else if (b3 || b4)
            {
                p1 = b3?selfstart:selfend;
                p2 = b3? selfend :selfstart;
                p3 = b3 ? otherstart:otherend;

                if (selfdir == -dir)
                {
                    return(false);
                }
                return(true);
            }
            return(false);
        }
Exemple #10
0
        int isInside(KInt2 p1, KInt2 p2, KInt2 p3, KInt2 target, int radius)
        {
            long A     = doublearea(p1, p2, p3);
            long A1    = doublearea(target, p2, p3);
            long A2    = doublearea(p1, target, p3);
            long A3    = doublearea(p1, p2, target);
            long delta = A - (A1 + A2 + A3);

            if (delta == 0)
            {
                return(1);
            }

            if (delta < radius && delta > -radius)
            {
                return(2);
            }
            return(-1);
        }
Exemple #11
0
        void ball_bbox_query(int nodeIdx, KInt2 pmin, KInt2 pmax, List <KInt2> inrange_idxs, List <float> distances, KInt2 point, float radiusSquared, int dim = 0)
        {
            GameKdTreeNode node = nodesPtrs[nodeIdx];

            // if it's a leaf and it lies in R
            if (node.isLeaf())
            {
                float distance = (points[node.pIdx] - point).sqrMagnitude;
                if (distance <= radiusSquared)
                {
                    bool insert = false;
                    for (int i = 0; i < distances.Count; ++i)
                    {
                        if (distance < distances[i])
                        {
                            insert = true;
                            distances.Insert(i, distance);
                            inrange_idxs.Insert(i, this.points[node.pIdx]);
                            break;
                        }
                    }

                    if (!insert)
                    {
                        distances.Add(distance);
                        inrange_idxs.Add(this.points[node.pIdx]);
                    }
                    return;
                }
            }
            else
            {
                if (node.key >= pmin[dim] && node.LIdx != -1)
                {
                    ball_bbox_query(node.LIdx, pmin, pmax, inrange_idxs, distances, point, radiusSquared, (dim + 1) % ndim);
                }
                if (node.key <= pmax[dim] && node.RIdx != -1)
                {
                    ball_bbox_query(node.RIdx, pmin, pmax, inrange_idxs, distances, point, radiusSquared, (dim + 1) % ndim);
                }
            }
        }
 public bool isSharedEdge(NavmeshTriangle other, out int idx)
 {
     for (int i = 0; i < 3; ++i)
     {
         KInt2 p1 = GetXZVertex(i);
         KInt2 p2 = GetXZVertex((i + 1) % 3);
         for (int k = 0; k < 3; ++k)
         {
             KInt2 p3 = other.GetXZVertex(k);
             KInt2 p4 = other.GetXZVertex((k + 1) % 3);
             if ((p1 == p3 && p2 == p4) || (p1 == p4 && p2 == p3))
             {
                 idx = i;
                 return(true);
             }
         }
     }
     idx = -1;
     return(false);
 }
        public void GetSegmentWithPoint(int idx, out KInt2 p1, out KInt2 p2)
        {
            if (idx > 2 || idx < 0)
            {
                throw new FrameWorkArgumentException("Get Segment Error");
            }

            if (idx == 0)
            {
                p1 = v03xz;
                p2 = v13xz;
            }
            else if (idx == 1)
            {
                p1 = v13xz;
                p2 = v23xz;
            }
            p1 = v23xz;
            p2 = v03xz;
        }
Exemple #14
0
        bool isAllLine(List <KInt2> linequeue)
        {
            if (linequeue.Count <= 2)
            {
                return(true);
            }

            KInt2 firstdir = linequeue [1] - linequeue [0];

            for (int i = 1; i < linequeue.Count - 1; ++i)
            {
                KInt2 current = linequeue [i];
                KInt2 next    = linequeue [i + 1];
                KInt  det     = RVOMath.det(next - current, firstdir);
                if (det != 0)
                {
                    return(false);
                }
            }
            return(true);
        }
Exemple #15
0
        public static bool Intersect(KInt2 p1, KInt2 p2, KInt2 p3, KInt2 p4, out KInt2 result)
        {
            result = KInt2.zero;
            float s1_x = p2.x - p1.x;
            float s1_y = p2.y - p1.y;
            float s2_x = p4.x - p3.x;
            float s2_y = p4.y - p3.y;

            float v1 = -s2_x * s1_y + s1_x * s2_y;
            float v2 = -s2_x * s1_y + s1_x * s2_y;
            float s  = (-s1_y * (p1.x - p3.x) + s1_x * (p1.y - p3.y)) / v1;
            float t  = (s2_x * (p1.y - p3.y) - s2_y * (p1.x - p3.x)) / v2;

            if (s >= 0 && s <= 1 && t >= 0 && t <= 1)
            {
                // Collision detected
                result = new KInt2((p1.x + t * s1_x), +(p1.y + t * s1_y));
                return(true);
            }

            return(false); // No collision
        }
Exemple #16
0
        bool TryConnectUntilFindTarget(KInt2 current, KInt2 target, List <KInt2> linequeue, HashSet <KInt2> openlist, Dictionary <KInt2, HashSet <KInt2> > connectlines)
        {
            openlist.Add(current);

            HashSet <KInt2> conncects = connectlines [current];

            if (conncects.Count > 0)
            {
                var en = conncects.GetEnumerator();
                while (en.MoveNext())
                {
                    KInt2 pt = en.Current;
                    if (linequeue.Count > 1)
                    {
                        if (pt.Equals(target))
                        {
                            linequeue.Add(target);
                            return(true);
                        }

                        if (openlist.Contains(pt))
                        {
                            continue;
                        }
                    }

                    linequeue.Add(pt);
                    if (TryConnectUntilFindTarget(pt, target, linequeue, openlist, connectlines))
                    {
                        return(true);
                    }
                    else
                    {
                        linequeue.Remove(pt);
                    }
                }
            }
            return(false);
        }
Exemple #17
0
        bool bounds_overlap_ball(KInt2 Xq)
        {
            // k-closest still not found. termination test unavailable
            if (pq.size() < k)
            {
                return(true);
            }

            float sum = 0;
            //extract best distance from queue top
            float best_dist_sq = pq.top().Key;

            // cout << "current best dist: " << best_dist_sq << endl;
            for (int d = 0; d < ndim; d++)
            {
                // lower than low boundary
                if (Xq[d] < Bmin[d])
                {
                    sum += (Xq[d] - Bmin[d]) * (Xq[d] - Bmin[d]);
                    if (sum > best_dist_sq)
                    {
                        return(false);
                    }
                }
                else if (Xq[d] > Bmax[d])
                {
                    sum += (Xq[d] - Bmax[d]) * (Xq[d] - Bmax[d]);
                    if (sum > best_dist_sq)
                    {
                        return(false);
                    }
                }
                // else it's in range, thus distance 0
            }

            return(true);
        }
Exemple #18
0
 public bool ContainsPoint(KInt2 point)
 {
     return(this.start == point || this.end == point);
 }
Exemple #19
0
        void RemoveUnused()
        {
            //sort
            BeginSample("SortByXcoordinate");
            SortByXcoordinate(segments);
            EndSample();
            BeginSample("connectlines check");
            HashSet <KInt2> allpoints = new HashSet <KInt2> ();
            Dictionary <KInt2, HashSet <KInt2> > connectlines = new Dictionary <KInt2, HashSet <KInt2> >(segments.Count);

            for (int i = 0; i < segments.Count; ++i)
            {
                Segment seg = segments [i];
                if (allpoints.Add(seg.start))
                {
                    connectlines [seg.start] = new HashSet <KInt2> ();
                }

                if (allpoints.Add(seg.end))
                {
                    connectlines [seg.end] = new HashSet <KInt2> ();
                }
            }


            KInt2 p1, p2, p3;

            for (int i = 0; i < segments.Count; ++i)
            {
                Segment firstline = segments [i];
                for (int j = i + 1; j < segments.Count; ++j)
                {
                    Segment secondline = segments [j];
                    if (firstline.MinX > secondline.MaxX)
                    {
                        break;
                    }

                    long maxminy = KMath.Max(firstline.MinY, secondline.MinY);
                    long minmaxy = KMath.Min(firstline.MaxY, secondline.MaxY);
                    if (maxminy > minmaxy)
                    {
                        continue;
                    }

                    if (Segment.isConnectRetPoints(firstline, secondline, out p1, out p2, out p3))
                    {
                        //only three point

                        connectlines [p1].Add(p2);
                        connectlines [p1].Add(p3);
                    }
                }

                ShowProgress("创建链接点", (float)i / segments.Count);
            }

            EndSample();
            this.segments.Clear();

            HashSet <Segment> realList    = new HashSet <Segment> ();
            List <KInt2>      linequeue   = new List <KInt2> (segments.Count);
            HashSet <KInt2>   openlist    = new HashSet <KInt2> ();
            HashSet <KInt2>   enabledlist = new HashSet <KInt2> ();

            BeginSample("combine polygon check");
            int progress = 0;
            var pointen  = allpoints.GetEnumerator();

            while (pointen.MoveNext())
            {
                KInt2 pt = pointen.Current;

                if (enabledlist.Contains(pt) || connectlines [pt].Count < 2)
                {
                    continue;
                }
                openlist.Clear();
                linequeue.Clear();

                linequeue.Add(pt);
                if (TryConnectUntilFindTarget(pt, pt, linequeue, openlist, connectlines))
                {
                    if (!isAllLine(linequeue))
                    {
                        AddtoList(realList, linequeue);
                        for (int k = 0; k < linequeue.Count; ++k)
                        {
                            enabledlist.Add(linequeue [k]);
                        }
                    }
                    else
                    {
#if UNITY_EDITOR
                        if (ObstacleDebug >= DebugMode.ShowAndLog)
                        {
                            LogMgr.LogFormat("准备剔除 原始目标点 为 :{0}", pt);
                            for (int k = 0; k < linequeue.Count; ++k)
                            {
                                LogMgr.LogFormat("准备剔除 :{0}", linequeue [k]);
                            }
                            LogMgr.Log("剔除结束");
                        }
#endif
                    }
                }
                progress++;
                ShowProgress("检测非多边形点", (float)progress / allpoints.Count);
            }
            EndSample();

            segments.Capacity = realList.Count;

            var realen = realList.GetEnumerator();
            while (realen.MoveNext())
            {
                segments.Add(realen.Current);
            }

            if (ExactMode >= ExactType.TWO)
            {
                BeginSample("PolygonIntersect");
                PolygonIntersect();
                EndSample();
            }
        }
Exemple #20
0
 static long cross(KInt2 p1, KInt2 p2, KInt2 p3)
 {
     return(p1.IntX * (p2.IntY - p3.IntY) + p2.IntX * (p3.IntY - p1.IntY) + p3.IntX * (p1.IntY - p2.IntY));
 }
Exemple #21
0
 long doublearea(KInt2 p1, KInt2 p2, KInt2 p3)
 {
     return(KMath.Abs((p1.IntX * (p2.IntY - p3.IntY) + p2.IntX * (p3.IntY - p1.IntY) + p3.IntX * (p1.IntY - p2.IntY))));
 }
Exemple #22
0
        void knn_search(KInt2 Xq, int nodeIdx = 0, int dim = 0)
        {
            // cout << "at node: " << nodeIdx << endl;
            GameKdTreeNode node = nodesPtrs[nodeIdx];
            float          temp;

            // We are in LEAF
            if (node.isLeaf())
            {
                float distance = (Xq - points[node.pIdx]).sqrMagnitude;

                // pqsize is at maximum size k, if overflow and current record is closer
                // pop further and insert the new one
                if (pq.size() == k && pq.top().Key > distance)
                {
                    pq.pop();                     // remove farther record
                    pq.push(distance, node.pIdx); //push new one
                }
                else if (pq.size() < k)
                {
                    pq.push(distance, node.pIdx);
                }

                return;
            }

            ////// Explore the sons //////
            // recurse on closer son
            if (Xq[dim] <= node.key)
            {
                temp = Bmax[dim]; Bmax[dim] = node.key;

                knn_search(Xq, node.LIdx, (dim + 1) % ndim);
                Bmax[dim] = temp;
            }
            else
            {
                temp = Bmin[dim]; Bmin[dim] = node.key;

                knn_search(Xq, node.RIdx, (dim + 1) % ndim);
                Bmin[dim] = temp;
            }
            // recurse on farther son
            if (Xq[dim] <= node.key)
            {
                temp = Bmin[dim]; Bmin[dim] = node.key;
                if (bounds_overlap_ball(Xq))
                {
                    knn_search(Xq, node.RIdx, (dim + 1) % ndim);
                }
                Bmin[dim] = temp;
            }
            else
            {
                temp = Bmax[dim]; Bmax[dim] = node.key;
                if (bounds_overlap_ball(Xq))
                {
                    knn_search(Xq, node.LIdx, (dim + 1) % ndim);
                }
                Bmax[dim] = temp;
            }
        }
Exemple #23
0
        bool Mesh2Obstacle()
        {
            if (mesh.vertexCount == 0 || mesh.triangles.Length == 0)
            {
                LogMgr.LogError("Convert Error");
                return(false);
            }
            BeginSample("Mesh2Obstacle");
            //old
            Vector3[] vectorVertices = mesh.vertices;
            int[]     triangles      = mesh.triangles;

            //create new
            KInt3[] vertices = new KInt3[mesh.vertexCount];

            Dictionary <KInt3, int> hashedVerts = new Dictionary <KInt3, int> (mesh.vertexCount);

            int[] newVertices = new int[vertices.Length];

            //从模型坐标系转换到世界坐标系
            for (int i = 0; i < vertices.Length; i++)
            {
                vertices [i] = (KInt3)MeshMatrix.MultiplyPoint3x4(vectorVertices [i]);
                ShowProgress("从模型坐标系转换到世界坐标系", (float)i / vertices.Length);
            }
            //旧顶点在新顶点中的索引
            int newVerIdx = 0;

            for (int i = 0; i < vertices.Length; i++)
            {
                //当hash 顶点集合不包含这个顶点的时候,把这个点加入进去,去除共点
                if (!hashedVerts.ContainsKey(vertices [i]))
                {
                    newVertices [newVerIdx] = i;
                    hashedVerts.Add(vertices [i], newVerIdx);
                    newVerIdx++;
                }
                ShowProgress("构建映射", (float)i / vertices.Length);
            }

            for (int x = 0; x < triangles.Length; x++)
            {
                //把老的顶点索引映射到新的顶点索引上
                KInt3 vertex = vertices [triangles [x]];

                triangles [x] = hashedVerts [vertex];
                ShowProgress("三角映射", (float)x / triangles.Length);
            }

            KInt3[] totalIntVertices = vertices;
            vertices = new KInt3[newVerIdx];
            for (int i = 0; i < newVerIdx; i++)
            {
                vertices [i] = totalIntVertices [newVertices [i]];
                ShowProgress("顶点索引转换", (float)i / newVerIdx);
            }
            //顶点创建结束
#if UNITY_EDITOR
            this.ObsVertices = vertices;
#endif
            if (triangles.Length % 3 != 0)
            {
                LogMgr.LogErrorFormat("triangle lenth error :{0}", triangles.Length);
            }

            //创建三角
            ObsTriangles = new NavmeshTriangle[triangles.Length / 3];

            for (int i = 0; i < ObsTriangles.Length; i++)
            {
                NavmeshTriangle tri = new NavmeshTriangle();
                ObsTriangles [i] = tri;
#if UNITY_EDITOR
                //init
                tri.uid = i;
#endif
                //
                tri.v0 = triangles [i * 3];
                tri.v1 = triangles [i * 3 + 1];
                tri.v2 = triangles [i * 3 + 2];

                if (RVOMath.IsClockwiseXZ(vertices [tri.v0], vertices [tri.v1], vertices [tri.v2]) == false)
                {
                    int tmp = tri.v0;
                    tri.v0 = tri.v2;
                    tri.v2 = tmp;
                }

                //finish position
                tri.v03 = vertices [tri.v0];
                tri.v13 = vertices [tri.v1];
                tri.v23 = vertices [tri.v2];

                tri.v03xz = new KInt2(tri.v03.x, tri.v03.z);
                tri.v13xz = new KInt2(tri.v13.x, tri.v13.z);
                tri.v23xz = new KInt2(tri.v23.x, tri.v23.z);

                tri.averagePos = (tri.v03 + tri.v13 + tri.v23) / 3;

                if (this.ExactMode >= ExactType.TWO)
                {
                    tri.xzPos = new KInt2(tri.averagePos.x, tri.averagePos.z);

                    if (point2triangle.ContainsKey(tri.xzPos))
                    {
                        point2triangle [tri.xzPos].Add(tri);
                    }
                    else
                    {
                        point2triangle [tri.xzPos] = new List <NavmeshTriangle> ();
                        point2triangle [tri.xzPos].Add(tri);
                    }
                }

                ShowProgress("构建三角形", (float)i / ObsTriangles.Length);
            }

            Dictionary <KInt2, NavmeshTriangle> sides = new Dictionary <KInt2, NavmeshTriangle> (triangles.Length * 3);

            //创建三角形的边
            for (int i = 0, j = 0; i < triangles.Length; j += 1, i += 3)
            {
                sides [KInt2.ToInt2(triangles [i + 0], triangles [i + 1])] = ObsTriangles [j];
                sides [KInt2.ToInt2(triangles [i + 1], triangles [i + 2])] = ObsTriangles [j];
                sides [KInt2.ToInt2(triangles [i + 2], triangles [i + 0])] = ObsTriangles [j];
            }

            HashSet <NavmeshTriangle> connections = new HashSet <NavmeshTriangle> ();

            for (int i = 0, j = 0; i < triangles.Length; j += 1, i += 3)
            {
                connections.Clear();

                NavmeshTriangle node = ObsTriangles [j];

                for (int q = 0; q < 3; q++)
                {
                    NavmeshTriangle other;
                    //如果是mesh中的边,则加入
                    if (sides.TryGetValue(KInt2.ToInt2(triangles [i + ((q + 1) % 3)], triangles [i + q]), out other))
                    {
                        connections.Add(other);
                    }
                }
                //拷贝当前的一份连接点,而不是赋值引用过去
                node.connections = new List <NavmeshTriangle> ();
                node.connections.AddRange(connections);

                node.CreateSharedInfo();
                ShowProgress("构建连接点", (float)i / (triangles.Length / 3));
            }
            ClearProgressBar();
            EndSample();

            return(true);
        }
Exemple #24
0
 public static bool isConnectRetPoints(Segment self, Segment other, out KInt2 p1, out KInt2 p2, out KInt2 p3)
 {
     return(isConnectRetPoints(self.start, self.end, other.start, other.end, out p1, out p2, out p3));
 }