/// <summary>
        /// distancetest判断两个stroke的距离
        /// 当且仅当两个stroke的都是线性的
        /// </summary>
        /// <param name="newstroke"></param>
        /// <returns></returns>
        public TESTRESULT DistanceTest(MyStroke newstroke, MyStroke prestroke)
        {
            if (prestroke == null || prestroke.linearity == Linearity.Curve)
                return TESTRESULT.SEPERATE;

            Point start1 = newstroke.adjustedPoints[0];
            Point end1 = newstroke.adjustedPoints[newstroke.adjustedPoints.Length - 1];
            Point start2 = prestroke.adjustedPoints[0];
            Point end2 = prestroke.adjustedPoints[prestroke.adjustedPoints.Length - 1];

            if (distanceP2P(start1, start2) < THRESHOLD_DISTANCE ||
                distanceP2P(start1, end2) < THRESHOLD_DISTANCE ||
                distanceP2P(end1, start2) < THRESHOLD_DISTANCE ||
                distanceP2P(end1, end2) < THRESHOLD_DISTANCE)
                return TESTRESULT.GROUP;
            else if
               (distanceP2L(start2, newstroke.m, -1, newstroke.c) < THRESHOLD_DISTANCE ||
                distanceP2L(end2, newstroke.m, -1, newstroke.c) < THRESHOLD_DISTANCE ||
                distanceP2L(start1, prestroke.m, -1, prestroke.c) < THRESHOLD_DISTANCE ||
                distanceP2L(end1, prestroke.m, -1, prestroke.c) < THRESHOLD_DISTANCE)
                return TESTRESULT.GROUP;
            else
                return TESTRESULT.SEPERATE;

        }
        /// <summary>
        /// 线性测试
        /// 判断stroke是直线或者曲线
        /// 如果是直线,将直线方程的参数写入到改stroke对象中
        /// 并且计算出改直线上每个点到其直线方程的垂足
        /// </summary>
        /// <param name="stroke"></param>
        /// <returns></returns>
        public Linearity LinearityTest(MyStroke stroke)
        {
            double linearity = 0;
            Point[] points = stroke.points;
            Point start = stroke.startPoint;
            Point end = stroke.endPoint;

            double sumofp2p = 0.0;
            for (int i = 1, j = points.Length; i < j; i++)
            {
                sumofp2p += distanceP2P(points[i], points[i - 1]);
            }

            linearity = distanceP2P(end, start) / sumofp2p;

            if (linearity >= THRESHOLD_LINEARITY)
            {
                stroke.linearity = Linearity.Line;//设置stroke的m和c属性
                computeMC(stroke);//为stroke添加m和c
                return Linearity.Line;
            }
            else
            {
                stroke.linearity = Linearity.Curve;
                return Linearity.Curve;
            }
        }
        /// <summary>
        /// angular test 判断两条直线的角度差别是否在threshold范围之内,
        /// 以判断他们是否可以分到一组
        /// </summary>
        /// <param name="newstroke"></param>
        /// <param name="prestroke"></param>
        /// <returns></returns>
        public TESTRESULT AngleTest(MyStroke newstroke, MyStroke prestroke)
        {
            if (prestroke == null || prestroke.linearity == Linearity.Curve)
                return TESTRESULT.SEPERATE;

            if (getAngleBetweenLine(newstroke.m, prestroke.m) < THRESHOLD_ANGULAR)
                return TESTRESULT.GROUP;
            else
                return TESTRESULT.SEPERATE;
        }
        //---------------------------------------------------------------------------------------
        //YHY-090421
        //判断一个stroke是否是近似圆
        public bool JudgeCircle(MyStroke stroke)
        {
            double dist = distanceP2P(stroke.startPoint, stroke.endPoint);

            double rationWtoH = 0;
            if (stroke.boundingBox.Width > stroke.boundingBox.Height && stroke.boundingBox.Height != 0)
                rationWtoH = stroke.boundingBox.Width / stroke.boundingBox.Height;
            else if (stroke.boundingBox.Height > stroke.boundingBox.Width && stroke.boundingBox.Width != 0)
                rationWtoH = stroke.boundingBox.Height / stroke.boundingBox.Width;

            double rationLenthtoBoundingbox;
            stroke.setLenth();
            rationLenthtoBoundingbox = stroke.lenth / ((stroke.boundingBox.Height + stroke.boundingBox.Width) * 2);

            if (dist < 1000 && rationWtoH < 1.5 && rationLenthtoBoundingbox < 0.9)
                return true;

            return false;
        }
Example #5
0
 /// <summary>
 /// 将mystroke从草图中删除
 /// 当stroke在某个strokegroup中的时候,将整个strokegroup删除
 /// </summary>
 /// <param name="mystroke"></param>
 public void deleteStroke(MyStroke mystroke)
 {
     if (!mystroke.isInGroup)
     {
         mystroke.inkstroke.Ink.DeleteStroke(mystroke.inkstroke);
         strokeList.Remove(mystroke);
     }
     else
     {
         if (mystroke.group != null)
         {
             deleteGroup(mystroke.group);
         }
     }
     if (mystroke == laststroke)
     {
         laststroke = strokeList.ToArray()[strokeList.Count - 1];
     }
 }
        /// <summary>
        /// 修正了bug
        /// 计算笔迹ms的方程y = mx + c的参数m和c
        /// </summary>
        /// <param name="ms"></param>
        public void computeMC(MyStroke ms)
        {
            ///只有ms是直线的时候才可以计算
            if (ms.linearity == Linearity.Curve)
                return;
            Point[] points = ms.points;
            double m = 0;
            double c = 0;
            double
                sumx2 = 0,
                sumx = 0,
                sumy = 0,
                sumxy = 0;

            Point pre = points[0];
            foreach (Point p in points)
            {
                int x = p.X, y = p.Y;
                sumx += x;
                sumy += y;
                sumx2 += x * x;
                sumxy += x * y;
            }

            m = (points.Length * sumxy - sumx * sumy) / (points.Length * sumx2 - sumx * sumx);
            c = (sumx2 * sumy - sumx * sumxy) / (points.Length * sumx2 - sumx * sumx);
            ms.m = m;
            ms.c = c;

            Point[] foots = new Point[points.Length];

            //拟合到直线上,计算每个点的垂足
            for (int i = 0; i < foots.Length; i++)
            {
                foots[i] = getFoot(points[i], m, -1, c);
            }
            ms.adjustedPoints = foots;

        }
        /// <summary>
        /// 计算两条直线之间的最短距离
        /// </summary>
        /// <param name="stroke1"></param>
        /// <param name="stroke2"></param>
        /// <returns></returns>
        public double distanceL2L(MyStroke stroke1, MyStroke stroke2)
        {
            Point[] ps1 = stroke1.adjustedPoints;
            Point[] ps2 = stroke2.adjustedPoints;

            Point start1 = ps1[0];
            Point end1 = ps1[ps1.Length - 1];
            Point start2 = ps2[0];
            Point end2 = ps2[ps2.Length - 1];

            double distance = distanceP2L(start1, stroke2.m, -1, stroke2.c);
            double distancetemp = 0;

            Point[] points = { start1, end1, start2, end2 };
            MyStroke[] strokes = { stroke1, stroke1, stroke2, stroke2 };
            for (int i = 0; i < points.Length; i++)
            {
                distancetemp = distanceP2L(points[i], strokes[i].m, -1, strokes[i].c);
                if (distancetemp < distance)
                    distance = distancetemp;
            }

            return distance;
        }
Example #8
0
        //////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// operations
        /// </summary>
        ///

        ///<summary>
        /// 在group中增加一个stroke
        /// 将stroke的时间设置为相同 这样通过时间轴回放的时候 会同时绘制group中的笔画
        /// </summary>
        ///
        public void addStroke(MyStroke myStroke)
        {
            strokeList.AddLast(myStroke);
            myStroke.isInGroup = true;
            myStroke.endTime   = this.StartTime;
            myStroke.group     = this;

            if (myStroke.linearity == Linearity.Curve)
            {
                return;
            }

            ///设置startPoint和endPoint
            Point p1 = myStroke.startPoint;
            Point p2 = myStroke.endPoint;

            if (strokeList.Count == 1)
            {
                if (p1.X < p2.X)
                {
                    startPoint = new Point(p1.X, p1.Y);
                    endPoint   = new Point(p2.X, p2.Y);
                }
                else
                {
                    startPoint = new Point(p2.X, p2.Y);
                    endPoint   = new Point(p1.X, p1.Y);
                }
            }
            else if (strokeList.Count > 1)
            {
                if (p1.X < p2.X)
                {
                    if (p1.X < startPoint.X)
                    {
                        startPoint.X = p1.X;
                        startPoint.Y = p1.Y;
                    }
                    if (p2.X > endPoint.X)
                    {
                        endPoint.X = p2.X;
                        endPoint.Y = p2.Y;
                    }
                }
                else
                {
                    if (p2.X < startPoint.X)
                    {
                        startPoint.X = p2.X;
                        startPoint.Y = p2.Y;
                    }
                    if (p1.X > endPoint.X)
                    {
                        endPoint.X = p1.X;
                        endPoint.Y = p1.Y;
                    }
                }
            }
            tool.computeSkeleton(this);
            computeSkeletonFromEnds();
        }
Example #9
0
 /// <summary>
 /// 从strokegroup中删除stroke
 /// </summary>
 /// <param name="myStroke"></param>
 public void removeStroke(MyStroke myStroke)
 {
     strokeList.Remove(myStroke);
 }
Example #10
0
        public void addStroke(Stroke stroke)
        {
            List <Stroke> changes   = new List <Stroke>();//需要刷新的stroke
            MyStroke      newstroke = new MyStroke(stroke);

            newstroke.setBoundingBox();                            //YHY-090412
            Sketch currentpage = sketch.currentpage.Value.content; //当前页

            ///线性测试
            if (tool.LinearityTest(newstroke) == Linearity.Line)
            {
                //新增加的stroke是直线
                ///straight-line segment fitting
                foreach (StrokeGroup strokegroup in currentpage.groupList)
                {
                    if (strokegroup.TYPE == GroupType.DEFAULT)
                    {
                        MyStroke mstroke = strokegroup.strokeList.First.Value;
                        if ((tool.DistanceTest(newstroke, mstroke) == TESTRESULT.GROUP) &&
                            (tool.AngleTest(newstroke, mstroke) == TESTRESULT.GROUP))
                        {
                            //通过了距离测试和角度测试
                            strokegroup.addStroke(newstroke);
                            drawingInk.Ink.DeleteStroke(strokegroup.Skeleton);
                            strokegroup.Skeleton = drawingInk.Ink.CreateStroke(strokegroup.SkeletonPoints);
                            strokegroup.Skeleton.DrawingAttributes = this.Skeleton_Attibute;
                            strokegroup.setBoundingBox();//YHY-090412
                            changes.Add(strokegroup.Skeleton);
                            break;
                        }
                    }
                }
                ///如果新增加的笔画没有找到组织,那么将给它单独建一个组
                if (!newstroke.isInGroup)
                {
                    //如果没有通过距离测试和角度测试
                    //Seperate Line
                    StrokeGroup sg = new StrokeGroup(GroupType.DEFAULT);
                    sketch.groupIndex++;
                    sg.groupID = sketch.groupIndex; //YHY-090413 增加一个标志
                    sg.addStroke(newstroke);
                    sg.Skeleton = drawingInk.Ink.CreateStroke(sg.SkeletonPoints);
                    sg.Skeleton.DrawingAttributes = this.Skeleton_Attibute;
                    //YHY-090410
                    sg.GRAPH = Graphic.Line;
                    sg.setBoundingBox();
                    sg.geometry = new G_Line(newstroke.startPoint, newstroke.endPoint);//YHY-090415

                    currentpage.addGroup(sg);

                    //判断新加入的strokegroup代表的图元和历史图元之间的约束关系
                    refreshConstraint(sg);

                    //yhy-090409
                    //将新建的group加入到skechContextDG中去
                    if (sketch.sketchContextDG.isEmpty())
                    {
                        sketch.sketchContextDG.nodeIndex++;
                        SKContextDGNode node = new SKContextDGNode(sg, sg.StartTime, sketch.sketchContextDG.nodeIndex);
                        node.groupID = sg.groupID;
                        sketch.sketchContextDG.newHead(node);
                        sketch.sketchContextDG.firstNode = node;
                        sketch.sketchContextDG.lastNode  = node;
                    }
                    else
                    {
                        sketch.sketchContextDG.addNode(sg);
                    }
                }

                //Groupping: add curve object to strokeGroup and sketch
                //YHY-090409
                ////////////////////////////////////////////////////////////////////////////////
                //YHY-090414
                //Just for test, ReGroup
                //sketchReGroupping();
                //drawBoundingBoxtoTestGrouppingResult();
                //////////////////////////////////////////////////////////////////////////////////


                /* StrokeGroup ngroup = newstroke.group;
                 *
                 * foreach (StrokeGroup group in currentpage.groupList)
                 * {
                 *  if (group == ngroup)
                 *      continue;
                 *
                 *  if (tool.distanceP2P(ngroup.startPoint, group.startPoint) < Threshold_Distance)
                 *  {
                 *      ngroup.startPoint = group.startPoint;
                 *      ngroup.computeSkeletonFromEnds();
                 *  }
                 *  else if (tool.distanceP2P(ngroup.startPoint, group.endPoint) < Threshold_Distance)
                 *  {
                 *      ngroup.startPoint = group.endPoint;
                 *      ngroup.computeSkeletonFromEnds();
                 *  }
                 *  else if (tool.distanceP2P(ngroup.endPoint, group.startPoint) < Threshold_Distance)
                 *  {
                 *      ngroup.endPoint = group.startPoint;
                 *      ngroup.computeSkeletonFromEnds();
                 *  }
                 *  else if (tool.distanceP2P(ngroup.endPoint, group.endPoint) < Threshold_Distance)
                 *  {
                 *      ngroup.endPoint = group.endPoint;
                 *      ngroup.computeSkeletonFromEnds();
                 *  }
                 * }*/
            }

            else if (tool.LinearityTest(newstroke) == Linearity.Curve)
            {
                //如果线性测试的结果是曲线

                //TODO::ToolForStroke.circle(et al).judge function
                //YHY-090408
                //先不考虑曲线补笔等草图特效的问题,假设所有曲线相关的sketch都是单笔的
                //判断是否为circle
                bool isCircle = false;
                isCircle = tool.JudgeCircle(newstroke);

                //YHY-090410
                //创建新的group,先不考虑曲线补笔等情况
                if (!newstroke.isInGroup)
                {
                    StrokeGroup sg = new StrokeGroup(GroupType.DEFAULT);
                    sketch.groupIndex++;
                    sg.groupID = sketch.groupIndex;
                    sg.addStroke(newstroke);
                    sg.setBoundingBox();

                    if (isCircle)
                    {
                        //TODO::暂时统一都认为是圆,以后需要改成椭圆
                        sg.GRAPH = Graphic.Circle;
                        Point  p = new Point();
                        double r;
                        p.X         = sg.boundingBox.Left + sg.boundingBox.Width / 2;
                        p.Y         = sg.boundingBox.Top + sg.boundingBox.Height / 2;
                        r           = System.Math.Min(sg.boundingBox.Height, sg.boundingBox.Width) / 2;
                        sg.geometry = new G_Cricle(p, r);//YHY-090415
                    }
                    else
                    {
                        sg.GRAPH = Graphic.Curve;
                    }

                    //sg.Skeleton = inkpicture.Ink.CreateStroke(sg.SkeletonPoints); //TODO: Get curve skeleton
                    //sg.Skeleton.DrawingAttributes = this.Skeleton_Attibute;
                    currentpage.addGroup(sg);

                    //捕捉约束
                    //判断新加入的strokegroup代表的图元和历史图元之间的约束关系
                    refreshConstraint(sg);


                    //yhy-090409
                    //将新建的group加入到skechContextDG中去
                    if (sketch.sketchContextDG.isEmpty())
                    {
                        sketch.sketchContextDG.nodeIndex++;
                        SKContextDGNode node = new SKContextDGNode(sg, sg.StartTime, sketch.sketchContextDG.nodeIndex);
                        node.groupID = sg.groupID;
                        sketch.sketchContextDG.newHead(node);
                        sketch.sketchContextDG.firstNode = node;
                        sketch.sketchContextDG.lastNode  = node;
                    }
                    else
                    {
                        sketch.sketchContextDG.addNode(sg);
                    }
                }

                //Groupping: add curve object to strokeGroup and sketch
                //YHY-090408
                ////////////////////////////////////////////////////////////////////////////////
                //YHY-090414
                //Just for test, ReGroup
                //   sketchReGroupping();
                //   drawBoundingBoxtoTestGrouppingResult();
                //////////////////////////////////////////////////////////////////////////////////



                //TODO::constraint capture function
                //如果未归为prior group,则需判断新添笔迹(group)与原来笔迹的约束关系
                //YHY-090416
                //判断新添加strokegroup里的图元和其余历史图元之间的关系
            }

            currentpage.addStroke(newstroke);
            ///对纸张进行局部更新
            if (stroke != null)
            {
                inkPanel.Invalidate(tool.InkSpaceToPixelRect(inkPanel.Handle, drawingInk.Renderer, stroke.GetBoundingBox()));
                foreach (Stroke st in changes)
                {
                    inkPanel.Invalidate(tool.InkSpaceToPixelRect(inkPanel.Handle, drawingInk.Renderer, st.GetBoundingBox()));
                }
            }
        }
Example #11
0
 /// <summary>
 /// 将stroke从sketch中删除
 /// </summary>
 /// <param name="mystroke"></param>
 public void removeStroke(MyStroke mystroke)
 {
     this.strokeList.Remove(mystroke);
 }
Example #12
0
        //////////////////////////////////////////////////////////////////////////////////
        ///operations
        ///

        ///<summary>
        /// 向sketch中增加stroke
        /// </summary>
        /// <param name="mystroke">需要增加的stroke</param>
        public void addStroke(MyStroke mystroke)
        {
            this.strokeList.Add(mystroke);
            this.laststroke = mystroke;
        }
        public double distanceStroketoStroke(MyStroke s1, MyStroke s2)
        {
            double minDist = 1000000;

            foreach (Point pt1 in s1.points)
            {
                foreach (Point pt2 in s2.points)
                {
                    double dist = P2P(pt1, pt2);
                    if (dist < minDist)
                    {
                        minDist = dist;
                    }
                }
            }


            //以下被封代码的距离计算公式来自于chiu 1998 paper

            /* double dx, dy;
             * double a = 1.2; //阈值, 需要确定
             *
             * dx = s2.boundingBox.Left - (s1.boundingBox.Left + s1.boundingBox.Width);
             * if (dx < 0)
             *     dx = 0;
             * dy = s2.boundingBox.Top - (s1.boundingBox.Top + s1.boundingBox.Height);
             * if (dy < 0)
             *     dy = 0;
             * dist = dx + a * dy; */

            //YHY-090412
            //Own

            /*    计算包围盒之间的最小距离方法
             *    Point p1 = new Point();
             *    Point p2 = new Point();
             *    double dist;
             *
             *    //================================
             *    p1.X = s1.boundingBox.Left;
             *    p1.Y = s1.boundingBox.Top;
             *    //
             *    p2.X = s2.boundingBox.Left;
             *    p2.Y = s2.boundingBox.Top;
             *    dist = P2P(p1, p2);
             *    if (dist < minDist)
             *        minDist = dist;
             *    //
             *    p2.X = s2.boundingBox.Right;
             *    p2.Y = s2.boundingBox.Top;
             *    dist = P2P(p1, p2);
             *    if (dist < minDist)
             *        minDist = dist;
             *    //
             *    p2.X = s2.boundingBox.Right;
             *    p2.Y = s2.boundingBox.Bottom;
             *    dist = P2P(p1, p2);
             *    if (dist < minDist)
             *        minDist = dist;
             *    //
             *    p2.X = s2.boundingBox.Left;
             *    p2.Y = s2.boundingBox.Bottom;
             *    dist = P2P(p1, p2);
             *    if (dist < minDist)
             *        minDist = dist;
             *
             *    //================================
             *    p1.X = s1.boundingBox.Right;
             *    p1.Y = s1.boundingBox.Top;
             *     //
             *    p2.X = s2.boundingBox.Left;
             *    p2.Y = s2.boundingBox.Top;
             *    dist = P2P(p1, p2);
             *    if (dist < minDist)
             *        minDist = dist;
             *    //
             *    p2.X = s2.boundingBox.Right;
             *    p2.Y = s2.boundingBox.Top;
             *    dist = P2P(p1, p2);
             *    if (dist < minDist)
             *        minDist = dist;
             *    //
             *    p2.X = s2.boundingBox.Right;
             *    p2.Y = s2.boundingBox.Bottom;
             *    dist = P2P(p1, p2);
             *    if (dist < minDist)
             *        minDist = dist;
             *    //
             *    p2.X = s2.boundingBox.Left;
             *    p2.Y = s2.boundingBox.Bottom;
             *    dist = P2P(p1, p2);
             *    if (dist < minDist)
             *        minDist = dist;
             *
             *    //================================
             *    p1.X = s1.boundingBox.Left;
             *    p1.Y = s1.boundingBox.Bottom;
             *    dist = P2P(p1, p2);
             *    if (dist < minDist)
             *        minDist = dist;
             *     //
             *    p2.X = s2.boundingBox.Left;
             *    p2.Y = s2.boundingBox.Top;
             *    dist = P2P(p1, p2);
             *    if (dist < minDist)
             *        minDist = dist;
             *    //
             *    p2.X = s2.boundingBox.Right;
             *    p2.Y = s2.boundingBox.Top;
             *    dist = P2P(p1, p2);
             *    if (dist < minDist)
             *        minDist = dist;
             *    //
             *    p2.X = s2.boundingBox.Right;
             *    p2.Y = s2.boundingBox.Bottom;
             *    dist = P2P(p1, p2);
             *    if (dist < minDist)
             *        minDist = dist;
             *    //
             *    p2.X = s2.boundingBox.Left;
             *    p2.Y = s2.boundingBox.Bottom;
             *    dist = P2P(p1, p2);
             *    if (dist < minDist)
             *        minDist = dist;
             *
             *    //================================
             *    p1.X = s1.boundingBox.Right;
             *    p1.Y = s1.boundingBox.Bottom;
             *    dist = P2P(p1, p2);
             *    if (dist < minDist)
             *        minDist = dist;
             *     //
             *    p2.X = s2.boundingBox.Left;
             *    p2.Y = s2.boundingBox.Top;
             *    dist = P2P(p1, p2);
             *    if (dist < minDist)
             *        minDist = dist;
             *    //
             *    p2.X = s2.boundingBox.Right;
             *    p2.Y = s2.boundingBox.Top;
             *    dist = P2P(p1, p2);
             *    if (dist < minDist)
             *        minDist = dist;
             *    //
             *    p2.X = s2.boundingBox.Right;
             *    p2.Y = s2.boundingBox.Bottom;
             *    dist = P2P(p1, p2);
             *    if (dist < minDist)
             *        minDist = dist;
             *    //
             *    p2.X = s2.boundingBox.Left;
             *    p2.Y = s2.boundingBox.Bottom;
             *    dist = P2P(p1, p2);
             *    if (dist < minDist)
             *        minDist = dist;*/

            return(minDist);
        }