예제 #1
0
        //型変換
        public static Poly ParsePolyFromQRCode(Procon2017MCTProtocol.SendablePolygon polygon, bool isPiece, sbyte initPieceId = -1)
        {
            int          i;
            List <Point> points = new List <Point>();
            List <Line>  lines  = new List <Line>();

            for (i = 0; i < polygon.Points.Count; i++)
            {
                points.Add(new Point(polygon.Points[i].X, polygon.Points[i].Y));
            }
            points.Add(points[0]);

            //表示する線分の設定 (ピースのみ)
            if (isPiece)
            {
                for (i = 0; i < points.Count - 1; i++)
                {
                    lines.Add(new Line(points[i], points[i + 1], initPieceId));
                }
            }

            Poly poly = new Poly(points, lines, isPiece, false);

            if (isPiece && poly.Area < 0)
            {
                poly.points.Reverse();
            }
            if (!isPiece && poly.Area > 0)
            {
                poly.points.Reverse();
            }
            return(poly);
        }
예제 #2
0
        //結合度計算
        //ピース同士ならO(N + M), 枠にピースを入れる場合は枠をM角形としてO(NM) (定数軽い)
        public static int Evaluation(Poly dstPoly, Poly srcPoly, int dstPointId, int srcPointId)
        {
            if (dstPoly.isPiece)
            {
                return(EvaluationSub(dstPoly, srcPoly, dstPointId, srcPointId));
            }
            else
            {
                double eps    = 1e-10;
                bool[] calced = new bool[srcPoly.Count];
                List <Tuple <Point, int> > pointList = new List <Tuple <Point, int> >();
                int score = 0;

                for (int i = 0; i < srcPoly.Count; i++)
                {
                    calced[i] = false;
                }
                for (int i = 0; i < dstPoly.Count; i++)
                {
                    pointList.Add(new Tuple <Point, int>(dstPoly.points[i], i));
                }
                pointList.Sort((a, b) => Point.Compare(a.Item1, b.Item1));

                for (int i = 0; i < srcPoly.Count; i++)
                {
                    if (calced[i])
                    {
                        continue;
                    }

                    int st = 0, ed = dstPoly.Count, mid;                        //oooxxxx
                    while (ed - st >= 2)
                    {
                        mid = (st + ed) / 2;
                        if (Point.Compare(pointList[mid].Item1, srcPoly.points[i]) <= 0)
                        {
                            st = mid;
                        }
                        else
                        {
                            ed = mid;
                        }
                    }
                    if (st == dstPoly.Count || (srcPoly.points[i] - pointList[st].Item1).Norm > eps)
                    {
                        continue;
                    }

                    //探索
                    score += EvaluationSub(dstPoly, srcPoly, pointList[st].Item2, i, calced);
                }
                return(score);
            }
        }
예제 #3
0
        //クローン (深いコピー)
        public Poly Clone()
        {
            Poly ret = new Poly(new List <Point>(points), new List <Line>(lines), isPiece, isPositionDetected);

            for (int i = 0; i < ret.lines.Count; i++)
            {
                ret.lines[i] = ret.lines[i].Clone();
            }
            ret.isPiece = this.isPiece;
            ret.isExist = this.isExist;
            return(ret);
        }
예제 #4
0
        //辺の追加
        private void AddEdgeTo(Line line, Poly dstPoly, Poly srcPoly)
        {
            double     eps     = 1e-5;
            List <int> pointId = new List <int>();

            for (int i = 0; i < pointList.Count; i++)
            {
                if (line.Distance(pointList[i]) <= eps)
                {
                    pointId.Add(i);
                }
            }

            for (int i = 0; i < pointId.Count - 1; i++)
            {
                for (int j = pointId.Count - 1; j > i; j--)
                {
                    double a = (pointList[pointId[j - 1]] - line.start).Norm;
                    double b = (pointList[pointId[j]] - line.start).Norm;
                    if (a > b)
                    {
                        int t = pointId[j - 1]; pointId[j - 1] = pointId[j]; pointId[j] = t;
                    }
                }
            }

            double dist = 1e-6 * 5;

            for (int i = 0; i < pointId.Count - 1; i++)
            {
                Point a   = pointList[pointId[i]];
                Point b   = pointList[pointId[i + 1]];
                Point mid = (a + b) / 2;
                Point l   = (b - a) * new Point(0, 1);  l /= l.Abs; l *= dist; l += mid;
                Point r   = (b - a) * new Point(0, -1); r /= r.Abs; r *= dist; r += mid;
                //右手が壁じゃなかったら辺をはる
                if (!IsWall(dstPoly, srcPoly, r))
                {
                    edgeTo[pointId[i]].Add(pointId[i + 1]);
                }
                if (!IsWall(dstPoly, srcPoly, l))
                {
                    edgeTo[pointId[i + 1]].Add(pointId[i]);
                }
            }
        }
예제 #5
0
        //線分が接触しているか
        public bool isHitLine(Poly poly)
        {
            List <Point> points = SizingPoly();

            for (int i = 0; i < Count; i++)
            {
                Line line1 = new Line(points[i], points[i + 1]);
                for (int j = 0; j < poly.Count; j++)
                {
                    Line line2 = new Line(poly.points[j], poly.points[j + 1]);
                    if (Line.IsHit(line1, line2))
                    {
                        return(true);
                    }
                }
            }
            return(false);
        }
예제 #6
0
 //点pointが壁に含まれるか?(境界の結果はPoly.isCover関数に依存)
 //壁の定義:
 //ピース同士の場合   … マージする2ピースの和領域
 //枠穴とピースの場合 … {枠穴 - ピース}以外の領域
 private bool IsWall(Poly dstPoly, Poly srcPoly, Point point)
 {
     if (dstPoly.isPiece)
     {
         return(dstPoly.isCover(point) || srcPoly.isCover(point));
     }
     else
     {
         if (srcPoly.isCover(point))
         {
             return(true);
         }
         else if (dstPoly.isCover(point))
         {
             return(false);
         }
         else
         {
             return(true);
         }
     }
 }
예제 #7
0
        //結合度計算のサブ(接している連続した部分1つについて、結合度を計算)
        //多角形dstPolyの頂点dstPointId, 多角形srcPolyの頂点srcPointIdが同じ位置にある。
        private static int EvaluationSub(Poly dstPoly, Poly srcPoly, int dstPointId, int srcPointId, bool[] calced = null)
        {
            const double eps = 1e-10;
            int          d   = dstPointId;
            int          s   = srcPointId;

            int[] count = { 0, 0, 0, 0 };   //count = {一致辺の個数, 始点と方向は一致してるが一致辺ではない辺の個数, 180°角の個数, 360°角の個数};
            int[] weight = { 4, 1, 2, 3 };  //weight…各項目の点数重み (定数)
            Point a, b;

            //走査1
            int counter = 0;

            while ((dstPoly[d] - srcPoly[s]).Norm <= eps && counter < dstPoly.Count)
            {
                if (calced != null)
                {
                    calced[toIndex(s, srcPoly.Count)] = true;
                }
                d++; s--; counter++;
            }

            //例外処理
            if (counter == dstPoly.Count)
            {
                return(dstPoly.Count * weight[0]);
            }                                                                                   //完全一致
            count[0] += d - dstPointId - 1;

            a = dstPoly[d] - dstPoly[d - 1];
            b = srcPoly[s] - srcPoly[s + 1];
            if (Math.Abs(Point.Cross(a, b)) <= eps)   //平行
            {
                if (Point.Dot(a, b) >= 0)
                {
                    count[1]++;
                }
                else
                {
                    count[2]++;
                }
            }

            //走査2
            d = dstPointId; s = srcPointId;
            while ((dstPoly[d] - srcPoly[s]).Norm <= eps)
            {
                if (calced != null)
                {
                    calced[toIndex(s, srcPoly.Count)] = true;
                }
                d--; s++;
            }
            count[0] += s - srcPointId - 1;

            a = dstPoly[d] - dstPoly[d + 1];
            b = srcPoly[s] - srcPoly[s - 1];
            if (Math.Abs(Point.Cross(a, b)) <= eps)   //平行
            {
                if (Point.Dot(a, b) >= 0)
                {
                    count[1]++;
                }
                else
                {
                    count[2]++;
                }
            }

            //角の個数は, count[0] + count[1] - 1で導出できる
            count[3] = count[0] + count[1] - 1;

            int score = 0;

            for (int i = 0; i < 4; i++)
            {
                score += weight[i] * count[i];
            }
            return(score);
        }
예제 #8
0
        //2多角形をマージする。srcPolyが移動してきた多角形(ピースであることが保証される)
        public List <Poly> Marge(Poly dstPoly, Poly srcPoly)
        {
            debugDstPoly = dstPoly;
            debugSrcPoly = srcPoly;
            pointList    = new List <Point>();
            for (int i = 0; i < dstPoly.Count; i++)
            {
                AddPointList(dstPoly.points[i]);
            }
            for (int i = 0; i < srcPoly.Count; i++)
            {
                AddPointList(srcPoly.points[i]);
            }

            edgeTo = new List <int> [pointList.Count];
            for (int i = 0; i < pointList.Count; i++)
            {
                edgeTo[i] = new List <int>();
            }
            for (int i = 0; i < dstPoly.Count; i++)
            {
                AddEdgeTo(new Line(dstPoly.points[i], dstPoly.points[i + 1]), dstPoly, srcPoly);
            }
            for (int i = 0; i < srcPoly.Count; i++)
            {
                AddEdgeTo(new Line(srcPoly.points[i], srcPoly.points[i + 1]), dstPoly, srcPoly);
            }
            used = new List <bool> [pointList.Count];
            for (int i = 0; i < pointList.Count; i++)
            {
                used[i] = new List <bool>();
            }
            for (int i = 0; i < pointList.Count; i++)
            {
                for (int j = 0; j < edgeTo[i].Count; j++)
                {
                    used[i].Add(false);
                }
            }

            //サイクル検出
            List <Poly> polys = new List <Poly>();
            List <Line> lines = new List <Line>();                  //実体をコピーします!

            if (dstPoly.isPiece)
            {
                for (int i = 0; i < dstPoly.lines.Count; i++)
                {
                    lines.Add(dstPoly.lines[i].Clone());
                }
                for (int i = 0; i < srcPoly.lines.Count; i++)
                {
                    lines.Add(srcPoly.lines[i].Clone());
                }
            }

            for (int i = 0; i < pointList.Count; i++)
            {
                for (int j = 0; j < edgeTo[i].Count; j++)
                {
                    if (used[i][j])
                    {
                        continue;
                    }
                    polys.AddRange(getPolys(i, j, dstPoly.isPiece, lines, srcPoly.isPositionDetected || dstPoly.isPositionDetected));
                }
            }

            //エラー処理
            if (dstPoly.isPiece && polys.Count > 1)
            {
                return(new List <Poly>());
            }                                                                                   //2ピースの内部に穴があるケース
            if (!dstPoly.isPiece && polys.Count == 0)
            {
                polys.Add(new Poly(new List <Point>(), lines, false, false)); return(polys);
            }                                                                                                                                           //枠穴に完全にピースが収まったケース

            //冗長点削除 + 辺生成
            List <Poly> ret = new List <Poly>();

            for (int i = 0; i < polys.Count; i++)
            {
                ret.Add(fixPoly(polys[i].points, lines, polys[i].isPiece, srcPoly.isPositionDetected || dstPoly.isPositionDetected));
            }
            return(ret);
        }