/// <summary>
        /// 始点がfromで終点がtoのエッジを戻す。
        /// </summary>
        private Edge FindEdge(PointInf from, PointInf to, FEOption opt)
        {
            switch (opt)
            {
            case FEOption.SamePointIdx:
                foreach (var e in mEdgeList)
                {
                    if (e.fromPointIdx == from.Idx &&
                        e.toPointIdx == to.Idx)
                    {
                        return(e);
                    }
                }
                break;

            case FEOption.SamePosition: {
                foreach (var e in mEdgeList)
                {
                    var e1 = mPP.FindPointByIdx(e.fromPointIdx, PointProc.FindPointMode.FindAll);
                    if (WWVectorD2.Distance(e1.xy, from.xy) < 1)
                    {
                        var e2 = mPP.FindPointByIdx(e.toPointIdx, PointProc.FindPointMode.FindAll);
                        if (WWVectorD2.Distance(e2.xy, to.xy) < 1)
                        {
                            return(e);
                        }
                    }
                }
            }
            break;
            }

            return(null);
        }
        /// <summary>
        /// エッジの矢印描画物作成。
        /// </summary>
        private Polygon NewArrowPoly(WWVectorD2 pos1, WWVectorD2 pos2, Brush stroke)
        {
            var dir2to1N = WWVectorD2.Sub(pos1, pos2).Normalize();
            var dir2to1S = dir2to1N.Scale(mDP.mArrowSz);

            // 2→1の方向と垂直のベクトル2つ。
            var dirA = new WWVectorD2(-dir2to1N.Y, dir2to1N.X).Scale(mDP.mArrowSz * 0.5);
            var dirB = new WWVectorD2(dir2to1N.Y, -dir2to1N.X).Scale(mDP.mArrowSz * 0.5);

            var vecA = WWVectorD2.Add(dir2to1S, dirA);
            var vecB = WWVectorD2.Add(dir2to1S, dirB);

            var pos2a = WWVectorD2.Add(pos2, dir2to1N.Scale(mDP.mPointSz / 2));
            var posA  = WWVectorD2.Add(pos2a, vecA);
            var posB  = WWVectorD2.Add(pos2a, vecB);

            var pc = new PointCollection();

            pc.Add(new Point(posB.X, posB.Y));
            pc.Add(new Point(pos2a.X, pos2a.Y));
            pc.Add(new Point(posA.X, posA.Y));

            var poly = new Polygon();

            poly.Points          = pc;
            poly.Fill            = stroke;
            poly.StrokeThickness = 0;
            return(poly);
        }
        /// <summary>
        /// 始点未決定状態で左クリック:始点を決定する。
        /// </summary>
        private void SetFirstPointLeftClicked(WWVectorD2 pos)
        {
            mPP.TmpFromPointRemove();

            // クリック地点に確定の点を作る。
            var pInf = mPP.TestHit(pos, mDP.mPointSz);

            if (pInf == null)
            {
                // クリックした場所には点は未だ無い。
                // 確定の始点を追加する → pInf。
                pInf = new PointInf(pos);
                var cmd = new Command(Command.CommandType.AddPoint, pInf, null);
                CommandDo(cmd);
                AddCmdToUndoList(new CommandAtomic(cmd));
                mPP.mFromPoint = pInf;
            }
            else
            {
                // クリック地点に確定の点あり。
                mPP.mFromPoint = pInf;
            }

            // エッジ追加モードに遷移。
            mMode = Mode.ModeAddEdge;
            UpdateDescription();
        }
        /// <summary>
        /// Edgeとposの最短距離を調べる。
        /// </summary>
        /// <param name="margin">1.0</param>
        public double EdgeDistanceFromPos(Edge e, WWVectorD2 pos, double margin, PointProc.FindPointMode fpm)
        {
            var p1 = mPP.FindPointByIdx(e.fromPointIdx, fpm);
            var p2 = mPP.FindPointByIdx(e.toPointIdx, fpm);

            return(WWSegmentPointDistance.SegmentPointDistance(p1.xy, p2.xy, pos, margin));
        }
        /// <summary>
        /// エッジの描画物を作り、キャンバスに登録。
        /// 描画物が無い状態で呼んで下さい。
        /// </summary>
        public void EdgeDrawablesCreate(Edge edge, Brush brush)
        {
            System.Diagnostics.Debug.Assert(edge.line == null);
            System.Diagnostics.Debug.Assert(edge.arrow == null);

            var p1 = mPP.FindPointByIdx(edge.fromPointIdx, PointProc.FindPointMode.FindAll);
            var p2 = mPP.FindPointByIdx(edge.toPointIdx, PointProc.FindPointMode.FindAll);

            edge.line  = DrawUtil.NewLine(p1.xy, p2.xy, brush);
            edge.arrow = NewArrowPoly(p1.xy, p2.xy, brush);

            Canvas.SetZIndex(edge.line, mDP.Z_Edge);
            Canvas.SetZIndex(edge.arrow, mDP.Z_Edge);
            mDP.mCanvas.Children.Add(edge.line);
            mDP.mCanvas.Children.Add(edge.arrow);

            // 文字を出す。
            var xy = WWVectorD2.Add(p1.xy, p2.xy).Scale(0.5);

            edge.tbIdx            = new TextBlock();
            edge.tbIdx.Padding    = new Thickness(2);
            edge.tbIdx.Text       = EdgeDescriptionText(edge.EdgeIdx, edge.C, edge.B);
            edge.tbIdx.Foreground = mDP.mEdgeTextFgBrush;
            edge.tbIdx.Background = mDP.mEdgeTextBgBrush;
            edge.tbIdx.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
            var tbWH = edge.tbIdx.DesiredSize;

            Canvas.SetLeft(edge.tbIdx, xy.X - tbWH.Width / 2);
            Canvas.SetTop(edge.tbIdx, xy.Y - tbWH.Height / 2);
            Canvas.SetZIndex(edge.tbIdx, mDP.Z_Edge + 1);
            mDP.mCanvas.Children.Add(edge.tbIdx);
        }
Exemple #6
0
        /// <summary>
        /// 新しいPointInfを作り、キャンバスに追加。
        /// 一時的な点用。
        /// </summary>
        public PointInf NewPoint(WWVectorD2 pos, Brush brush)
        {
            var pInf = new PointInf(pos);

            PointDrawableCreate(pInf, brush);
            return(pInf);
        }
        public void SegmentPointDistanceTestY2()
        {
            var edgeP1 = new WWVectorD2(0, 1);
            var edgeP2 = new WWVectorD2(0, 0);
            var point  = new WWVectorD2(1, 0.5);

            double d = WWSegmentPointDistance.SegmentPointDistance(edgeP1, edgeP2, point, 1e-8);

            Assert.IsTrue(IsApproxSame(d, 1));
        }
 /// <summary>
 /// 始点決定状態で右クリック:始点が未決定の状態に遷移。
 /// </summary>
 private void PointAddRightClicked(WWVectorD2 pos)
 {
     TmpDrawablesRemove((int)TmpDrawablesRemoveOpt.RemoveAll);
     if (mMode == Mode.ModeAddEdge)
     {
         // Edge追加モードのとき、始点設定モードに遷移。
         mMode = Mode.ModeSetFirstPoint;
         UpdateDescription();
     }
 }
        public void SegmentPointDistanceTest2()
        {
            var edgeP1 = new WWVectorD2(1, 0);
            var edgeP2 = new WWVectorD2(1, 1);
            var point  = new WWVectorD2(2, 2);

            double d = WWSegmentPointDistance.SegmentPointDistance(edgeP1, edgeP2, point, 1e-8);

            Assert.IsTrue(IsApproxSame(d, Math.Sqrt(2)));
        }
Exemple #10
0
        /// <summary>
        /// 線描画物作成。
        /// </summary>
        public static Line NewLine(WWVectorD2 xy1, WWVectorD2 xy2, Brush stroke)
        {
            var l = new Line();

            l.X1     = xy1.X;
            l.Y1     = xy1.Y;
            l.X2     = xy2.X;
            l.Y2     = xy2.Y;
            l.Stroke = stroke;
            return(l);
        }
Exemple #11
0
        /// <summary>
        /// リストに点xyが存在するか。
        /// </summary>
        private bool PointExists(List <PointInf> points, WWVectorD2 xy)
        {
            foreach (var p in points)
            {
                if (WWVectorD2.Distance(p.xy, xy) < 1)
                {
                    return(true);
                }
            }

            return(false);
        }
Exemple #12
0
        /// <returns>既存の点と当たったら既存点のPointInfを戻す。</returns>
        public PointInf TestHit(WWVectorD2 xy, double threshold)
        {
            foreach (var p in mPointList)
            {
                if (WWVectorD2.Distance(p.xy, xy) < threshold)
                {
                    return(p);
                }
            }

            return(null);
        }
        /// <summary>
        /// マウス移動イベントハンドラー。
        /// </summary>
        private void mCanvas_MouseMove(object sender, MouseEventArgs e)
        {
            var posExact = e.GetPosition(mCanvas);

            if (mPrevPos != null && WWVectorD2.Distance(mPrevPos,
                                                        new WWVectorD2(posExact.X, posExact.Y)) < 1.0)
            {
                // マウス移動量が小さい場合、何もしない。
                return;
            }
            mPrevPos = new WWVectorD2(posExact.X, posExact.Y);

            CanvasMouseMove(e);
        }
        /// <summary>
        /// エッジの係数が変更された。
        /// </summary>
        public void EdgeParamChanged(Edge edge, double newC, double newB)
        {
            edge.tbIdx.Text = EdgeDescriptionText(edge.EdgeIdx, newC, newB);

            // 表示位置を調整する。
            var p1 = mPP.FindPointByIdx(edge.fromPointIdx, PointProc.FindPointMode.FindAll);
            var p2 = mPP.FindPointByIdx(edge.toPointIdx, PointProc.FindPointMode.FindAll);
            var xy = WWVectorD2.Add(p1.xy, p2.xy).Scale(0.5);

            edge.tbIdx.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
            var tbWH = edge.tbIdx.DesiredSize;

            Canvas.SetLeft(edge.tbIdx, xy.X - tbWH.Width / 2);
            Canvas.SetTop(edge.tbIdx, xy.Y - tbWH.Height / 2);
        }
        /// <summary>
        /// 始点か終点がposのエッジを戻す。
        /// </summary>
        private Edge FindEdge(WWVectorD2 pos)
        {
            foreach (var e in mEdgeList)
            {
                var p1 = mPP.FindPointByIdx(e.fromPointIdx, PointProc.FindPointMode.FindAll);
                var p2 = mPP.FindPointByIdx(e.toPointIdx, PointProc.FindPointMode.FindAll);

                if (WWVectorD2.Distance(pos, p1.xy) < 1)
                {
                    return(e);
                }
                if (WWVectorD2.Distance(pos, p2.xy) < 1)
                {
                    return(e);
                }
            }

            return(null);
        }
        /// <summary>
        /// posに近い場所を横切るEdgeを調べる。
        /// </summary>
        public Edge FindNearestEdge(WWVectorD2 pos)
        {
            Edge   nearestEdge     = null;
            double nearestDistance = double.MaxValue;
            double margin          = 1.0;

            foreach (var e in mEdgeList)
            {
                double distance = EdgeDistanceFromPos(e, pos, margin, PointProc.FindPointMode.FindAll);
                if (distance < nearestDistance)
                {
                    // 現時点で最も距離が近いエッジ。
                    nearestDistance = distance;
                    nearestEdge     = e;
                }
            }

            return(nearestEdge);
        }
        private void DeletePointEdgeMouseMove(WWVectorD2 pos)
        {
            // 選択状態色を一旦通常色に戻します。
            DeletePointEdgeCancel();

            var e = mEP.FindNearestEdge(pos);
            var p = mPP.TestHit(pos, mDP.mPointSz);

            if (e != null)
            {
                if (p != null)
                {
                    // 近いほうがヒット。
                    if (mEP.EdgeDistanceFromPos(e, pos, 1.0, PointProc.FindPointMode.FindFromPointList)
                        < WWVectorD2.Distance(p.xy, pos))
                    {
                        // eのほうが近い。
                        mEP.EdgeChangeColor(e, mDP.mBrightBrush);
                        mEP.mTmpEdge = e;
                    }
                    else
                    {
                        // pのほうが近い。
                        mPP.PointChangeColor(p, mDP.mBrightBrush);
                        mPP.mFromPoint = p;
                    }
                }
                else
                {
                    // エッジ。
                    mEP.EdgeChangeColor(e, mDP.mBrightBrush);
                    mEP.mTmpEdge = e;
                }
            }
            else if (p != null)
            {
                // p。
                mPP.PointChangeColor(p, mDP.mBrightBrush);
                mPP.mFromPoint = p;
            }
        }
Exemple #18
0
        // ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
        // イベント。

        public void MouseMoveUpdateTmpPoint(WWVectorD2 pos)
        {
            if (mFromPoint == null)
            {
                // 始点が無い。
                Console.WriteLine("MMP FP none");
                return;
            }

            // 始点有り。
            Console.WriteLine("MMP ({0:0.0} {0:0.0})", pos.X, pos.Y);

            var toPoint = TestHit(pos, mDP.mPointSz);

            if (toPoint == null)
            {
                // 始点が存在し、マウスポインタ位置に確定の終点が無い。
                if (mToPoint != null && WWVectorD2.Distance(mToPoint.xy, pos) < 1)
                {
                    // マウスポインタ位置に仮の終点mToPointが存在。
                    Console.WriteLine("MMP already toPoint");
                }
                else
                {
                    // 仮の終点位置が異なるので作り直す。
                    PointDrawableRemove(mToPoint);
                    mToPoint = null;
                    mToPoint = NewPoint(pos, mDP.mBrightBrush);
                    Console.WriteLine("MMP create toPoint");
                }
            }
            else
            {
                // マウスポインタ位置に確定の終点が存在する。
                // 仮の終点は不要。
                PointDrawableRemove(mToPoint);
                mToPoint = null;
            }
        }
        /// <summary>
        /// 削除モード:点またはエッジを消す
        /// </summary>
        private void DeletePointEdgeLeftClicked(WWVectorD2 pos)
        {
            DeletePointEdgeCancel();

            var e = mEP.FindNearestEdge(pos);
            var p = mPP.TestHit(pos, mDP.mPointSz);

            if (e != null)
            {
                if (p != null)
                {
                    // 近いほうがヒット。
                    if (mEP.EdgeDistanceFromPos(e, pos, 1.0, PointProc.FindPointMode.FindFromPointList)
                        < WWVectorD2.Distance(p.xy, pos))
                    {
                        // eのほうが近い。
                        DeleteEdge(e);
                    }
                    else
                    {
                        // pのほうが近い。
                        DeletePoint(p);
                    }
                }
                else
                {
                    // エッジ。
                    DeleteEdge(e);
                }
            }
            else if (p != null)
            {
                // p。
                DeletePoint(p);
            }
        }
        /// <summary>
        /// 始点がidxFromで終点がidxToのエッジを戻す。
        /// </summary>
        public Edge FindEdge(int idxFrom, int idxTo, FEOption opt)
        {
            switch (opt)
            {
            case FEOption.SamePointIdx:
                foreach (var e in mEdgeList)
                {
                    if (e.fromPointIdx == idxFrom &&
                        e.toPointIdx == idxTo)
                    {
                        return(e);
                    }
                }
                break;

            case FEOption.SamePosition: {
                var p1 = mPP.FindPointByIdx(idxFrom, PointProc.FindPointMode.FindAll);
                var p2 = mPP.FindPointByIdx(idxTo, PointProc.FindPointMode.FindAll);
                foreach (var e in mEdgeList)
                {
                    var e1 = mPP.FindPointByIdx(e.fromPointIdx, PointProc.FindPointMode.FindAll);
                    if (WWVectorD2.Distance(e1.xy, p1.xy) < 1)
                    {
                        var e2 = mPP.FindPointByIdx(e.toPointIdx, PointProc.FindPointMode.FindAll);
                        if (WWVectorD2.Distance(e2.xy, p2.xy) < 1)
                        {
                            return(e);
                        }
                    }
                }
            }
            break;
            }

            return(null);
        }
        /// <summary>
        /// 始点決定状態で左クリック:終点を決定する。始点から終点に向かうエッジを追加。終点が新たに始点となる。
        ///   既存点を左クリックしたとき、点の追加を行わずエッジを追加する。
        /// </summary>
        private void PointAddLeftClicked(WWVectorD2 pos)
        {
            if (pos.X < 0 || mCanvas.ActualWidth <= pos.X ||
                pos.Y < 0 || mCanvas.ActualHeight <= pos.Y)
            {
                // Canvas外のクリック。
                return;
            }

            // 始点決定状態。
            System.Diagnostics.Debug.Assert(mPP.mFromPoint != null);

            // 始点決定状態で左クリック:終点を決定する。始点から終点に向かうエッジを追加。終点が新たに始点となる。
            // 既存点を左クリックしたとき、点の追加を行わずエッジを追加する。

            var ca = new CommandAtomic();

            // クリック地点に確定点が存在するか?
            var pInf = mPP.TestHit(pos, mDP.mPointSz);

            if (pInf == null)
            {
                // クリックした場所には確定点は未だ無い。

                // 仮の終点を削除。
                TmpDrawablesRemove((int)TmpDrawablesRemoveOpt.RemoveToPoint);
                mPP.mToPoint = null;

                // 確定の終点を追加する。
                pInf = new PointInf(pos);
                var cmd = new Command(Command.CommandType.AddPoint, pInf, null);
                CommandDo(cmd);
                ca.Add(cmd);
            }
            else if (WWVectorD2.Distance(pInf.xy, mPP.mFromPoint.xy) < 0.5)
            {
                // クリックした点が、始点と同じ点。
                // 特に何もしないで戻る。
                return;
            }

            // クリック地点に始点とは異なる終点pInfが存在する状態。
            // 始点の色を通常色にする。
            mPP.PointChangeColor(mPP.mFromPoint, mDP.mBrush);

            var edge = mEP.FindEdge(mPP.mFromPoint.Idx, pInf.Idx, EdgeProc.FEOption.SamePosition);

            if (edge == null)
            {
                // 始点→終点のエッジが無いので追加。
                var cmd = new Command(Command.CommandType.AddEdge, null, new Edge(mPP.mFromPoint.Idx, pInf.Idx));
                CommandDo(cmd);
                ca.Add(cmd);
            }

            // コマンドが集まったのでアンドゥーリストに足す。
            if (0 < ca.commandList.Count)
            {
                AddCmdToUndoList(ca);
            }

            // クリックした点を新たな始点にする。
            mPP.mFromPoint = pInf;
            mPP.PointChangeColor(mPP.mFromPoint, mDP.mBrightBrush);
        }
 /// <summary>
 /// 始点が存在し、マウスがホバーしているとき、一時的エッジの描画位置を更新する。
 /// </summary>
 private void TmpEdgeRedrawMouseMove(WWVectorD2 pos)
 {
     mPP.MouseMoveUpdateTmpPoint(pos);
     mEP.MouseMoveUpdateTmpEdge(pos);
 }
Exemple #23
0
 /// <summary>
 /// 点。Idx, 位置aXYと描画物がある。
 /// </summary>
 public PointInf(WWVectorD2 aXY)
 {
     idx = mNextPointIdx++;
     xy  = aXY;
     F   = 0;
 }
Exemple #24
0
        /// <summary>
        /// 始点が未決定の状態でマウスがホバーしている。
        /// </summary>
        public void SetFirstPointMouseMove(WWVectorD2 pos)
        {
            var point = TestHit(pos, mDP.mPointSz);

            if (mFromPoint == null)
            {
                // 始点が無い。
                Console.WriteLine("SFPMM FP none");

                if (point == null)
                {
                    // 始点mFromPointが無く、マウスホバー位置に確定の点も無い。
                    // マウスポインタ位置に仮の始点を作る。
                    mFromPoint = NewPoint(pos, mDP.mBrightBrush);
                    Console.WriteLine("SFPMM create fromPoint");
                    return;
                }

                // 始点が無く、マウスホバー位置に確定の点が有る。
                // 確定の点の色をハイライト色に変更。
                // mFromPointをセットする。
                mFromPoint = point;
                PointChangeColor(mFromPoint, mDP.mBrightBrush);
                return;
            }

            // 始点mFromPoint有り。
            Console.WriteLine("SFPMM ({0:0.0} {0:0.0})", pos.X, pos.Y);

            if (point == null)
            {
                // 始点mFromPointが存在し、マウスポインタ位置に確定の点が無い。

                if (WWVectorD2.Distance(mFromPoint.xy, pos) < 1)
                {
                    // マウスポインタ位置に仮の始点mFromPointが存在。
                    Console.WriteLine("SFPMM no need to change tmp FromPoint");
                }
                else
                {
                    // 仮の始点位置が異なるので作り直す。
                    TmpFromPointRemove();
                    mFromPoint = NewPoint(pos, mDP.mBrightBrush);
                    Console.WriteLine("SFPMM create FromPoint");
                }
            }
            else
            {
                // 始点mFromPointが存在し、マウスホバー位置に確定の始点pointが存在する。
                Console.WriteLine("SFPMM remove tmp drawable and set point");

                // 始点mFromPointが仮の点のときは消す。
                TmpFromPointRemove();

                // マウスホバー位置の確定の点をmFromPointにセットする。
                // 確定の点の色をハイライト色に変更。
                // mFromPointをセットする。
                mFromPoint = point;
                PointChangeColor(mFromPoint, mDP.mBrightBrush);
                return;
            }
        }
        // ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
        // イベント。

        public void MouseMoveUpdateTmpEdge(WWVectorD2 pos)
        {
            if (mPP.mFromPoint == null)
            {
                // 始点が無い。
                Console.WriteLine("MME FP none");
                return;
            }

            // 始点mFromPoint有り。
            Console.WriteLine("MME ({0:0.0} {0:0.0})", pos.X, pos.Y);

            // TmpEdgeの始点p1と終点p2
            PointInf p1 = null;
            PointInf p2 = null;

            if (mTmpEdge != null)
            {
                p1 = mPP.FindPointByIdx(mTmpEdge.fromPointIdx, PointProc.FindPointMode.FindAll);
                p2 = mPP.FindPointByIdx(mTmpEdge.toPointIdx, PointProc.FindPointMode.FindAll);
            }

            // マウスポインタ位置に確定の終点toPointがあるか。
            var toPoint = mPP.TestHit(pos, mDP.mPointSz);

            if (toPoint == null)
            {
                // マウスポインタ位置に確定の終点が無い。
                // この場合、確定のエッジは無い。
                if (mPP.mToPoint != null && WWVectorD2.Distance(mPP.mToPoint.xy, pos) < 1)
                {
                    // マウスポインタ位置に仮の終点mToPointが存在する。
                    Console.WriteLine("MME already toPoint");

                    if (p1 == mPP.mFromPoint && p2 == mPP.mToPoint)
                    {
                        // mFromPoint → mToPoint
                        // 仮のエッジが既に引かれている。
                        return;
                    }

                    // mFromPoint → mToPointのエッジを引く必要がある。
                    p1 = mPP.mFromPoint;
                    p2 = mPP.mToPoint;
                }
                else
                {
                    // マウスポインタ位置に確定の終点も仮の終点も無い。
                    // 画面外にマウスが行った場合?
                    // 仮のエッジがあれば消す。
                    EdgeDrawablesRemove(mTmpEdge);
                    return;
                }
            }
            else
            {
                // 確定の終点toPointがある。
                if (null != FindEdge(mPP.mFromPoint.Idx, toPoint.Idx, FEOption.SamePosition))
                {
                    // 確定のエッジが既に引かれている。
                    // 仮のエッジがあれば消す。
                    EdgeDrawablesRemove(mTmpEdge);
                    return;
                }

                if (p1 == mPP.mFromPoint && p2 == toPoint)
                {
                    // mFromPoint → toPoint
                    // 仮のエッジが既に引かれている。
                    return;
                }

                // mFromPoint → toPointのエッジを引く必要がある。
                p1 = mPP.mFromPoint;
                p2 = toPoint;
            }

            // Edgeを作り直す。
            EdgeDrawablesRemove(mTmpEdge);
            mTmpEdge = NewEdge(p1, p2, mDP.mBrightBrush);
            Console.WriteLine("MME created edge");
            return;
        }