public void addNode(StrokeGroup sg) { /* * 1. 如果SKContextDG为空,创建关于s新节点nodeS,算法结束; * 2. 创建新节点nodeS,计算笔迹s与前一输入笔迹s’的输入时间差deltTime; * 3. 如果deltTime < ThresholdTime,将前一输入笔迹s所对应的节点的tPointer指针指向nodeS; * 4. 顺次遍历SKContextDG的历史节点,计算nodeS与历史节点的空间距离dist,根据dist’值判断二者之间的空间关系R; * 5. 如果R= ST,在两个节点之间建立空间关联链接,重复步骤4直至遍历完所有节点。 */ nodeIndex++; SKContextDGNode node = new SKContextDGNode(sg, sg.StartTime, nodeIndex); DGNodeList.Add(node); node.groupID = sg.groupID; double thresholdTime = 1.2; //TODO::阈值的确定 double thresholdSpatial = 1000; //TODO::阈值的确定 //空间邻近关系建立 double dist = -1; dist = distance(sg, lastNode.strokeGroup); if ((dist > thresholdSpatial) && (!DGHeadList.Contains(node))) { newHead(node); } foreach (SKContextDGNode preNode in DGNodeList) { if (preNode != node) { StrokeGroup preSg = null; preSg = preNode.strokeGroup; dist = distance(sg, preSg); if ((dist < thresholdSpatial) && (!node.sPointer.Contains(preNode))) { node.sPointer.Add(preNode); } } } //时间邻近关系建立 double delta = (long)((TimeSpan)(sg.StartTime - lastNode.timeStamp)).TotalSeconds; if (delta < thresholdTime) { //时间邻近 lastNode.tPointer = node; } else if (!DGHeadList.Contains(node)) { newHead(node); } lastNode = node; }
public SKContextDGNode(StrokeGroup sg, DateTime time, int nodeIndex) { strokeGroup = sg; timeStamp = time; ID = nodeIndex; tPointer = null; }
///<summary> ///将group删除掉 ///</summary> public void deleteGroup(StrokeGroup strokegroup) { foreach (MyStroke stroke in strokegroup.strokeList) { stroke.inkstroke.Ink.DeleteStroke(stroke.inkstroke); strokeList.Remove(stroke); } groupList.Remove(strokegroup); }
public double distance(StrokeGroup sg1, StrokeGroup sg2) { double mindist = 10000; double dist; foreach (MyStroke stroke1 in sg1.strokeList) { foreach (MyStroke stroke2 in sg2.strokeList) { dist = distanceStroketoStroke(stroke1, stroke2); if (dist < mindist) { mindist = dist; } } } return(mindist); }
/// <summary> /// 计算group的skeleton方程 y = mx +c /// 将结果m和c保存到strokegroup数据结构中 /// </summary> /// <param name="group"></param> public void computeSkeleton(StrokeGroup group) { LinkedList<MyStroke> sts = group.strokeList; List<Point> ptlist = new List<Point>(); foreach (MyStroke ms in sts) { Point[] points = ms.points; foreach (Point p in points) { ptlist.Add(p); } } Point[] pts = ptlist.ToArray(); double m = 0; double c = 0; double sumx2 = 0, sumx = 0, sumy = 0, sumxy = 0; foreach (Point p in pts) { int x = p.X, y = p.Y; sumx += x; sumy += y; sumx2 += x * x; sumxy += x * y; } m = (pts.Length * sumxy - sumx * sumy) / (pts.Length * sumx2 - sumx * sumx); c = (sumx2 * sumy - sumx * sumxy) / (pts.Length * sumx2 - sumx * sumx); group.m = m; group.c = c; }
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())); } } }
public void refreshConstraint(StrokeGroup sg) { bool isL_L_Vertical = false; bool isL_L_Intersect = false; bool isL_L_Parallel = false; bool isL_C_Tangent = false; bool isL_C_Intersect = false; bool isL_C_LineInCircle = false; //TODO::加入更多的约束关系 if (sg.GRAPH == Graphic.Line) { G_Line geo1 = (G_Line)sg.geometry; foreach (SKContextDGNode nd in sketch.sketchContextDG.DGNodeList) { Graphic type = nd.strokeGroup.GRAPH; switch (type) { case Graphic.Line: //L_L G_Line geo2 = (G_Line)nd.strokeGroup.geometry; if (geo2 != null) { isL_L_Vertical = new G_L_L_Constraints().L_L_Vertical(geo1, geo2); isL_L_Intersect = new G_L_L_Constraints().L_L_Intersect(geo1, geo2); isL_L_Parallel = new G_L_L_Constraints().L_L_Parallel(geo1, geo2); //保存约束 ConstraintElement elem = new ConstraintElement(); elem.strokeGroup1 = sg; elem.strokeGroup2 = nd.strokeGroup; if (isL_L_Intersect) { elem.ctype = ConstraintType.Intersect; sketch.m_pConsList.Add(elem); // MessageBox.Show("Intersecting"); } if (isL_L_Parallel) { elem.ctype = ConstraintType.Parallel; sketch.m_pConsList.Add(elem); // MessageBox.Show("Parallel"); } if (isL_L_Vertical) { elem.ctype = ConstraintType.Vertical; sketch.m_pConsList.Add(elem); // MessageBox.Show("Vertical"); } } break; case Graphic.Circle: //L_C G_Cricle geo3 = (G_Cricle)nd.strokeGroup.geometry; if (geo3 != null) { isL_C_Tangent = new G_L_C_Constraints().L_C_Tangent(); isL_C_Intersect = new G_L_C_Constraints().L_C_Intesect(geo1, geo3); isL_C_LineInCircle = new G_L_C_Constraints().L_C_LineInCircle(geo1, geo3); //保存约束 ConstraintElement elem1 = new ConstraintElement(); elem1.strokeGroup1 = sg; elem1.strokeGroup2 = nd.strokeGroup; if (isL_C_Tangent) { elem1.ctype = ConstraintType.Tangent; sketch.m_pConsList.Add(elem1); // MessageBox.Show("Intersecting"); } if (isL_C_Intersect) { elem1.ctype = ConstraintType.Intersect; sketch.m_pConsList.Add(elem1); // MessageBox.Show("Parallel"); } if (isL_C_LineInCircle) { elem1.ctype = ConstraintType.In; sketch.m_pConsList.Add(elem1); // MessageBox.Show("Vertical"); } } break; default: break; } } } else if (sg.GRAPH == Graphic.Circle) //Circle { G_Cricle geo4 = (G_Cricle)sg.geometry; foreach (SKContextDGNode nd in sketch.sketchContextDG.DGNodeList) { Graphic type = nd.strokeGroup.GRAPH; switch (type) { case Graphic.Line: //L_C G_Line geo5 = (G_Line)nd.strokeGroup.geometry; if (geo5 != null) { isL_C_Tangent = new G_L_C_Constraints().L_C_Tangent(); isL_C_Intersect = new G_L_C_Constraints().L_C_Intesect(geo5, geo4); isL_C_LineInCircle = new G_L_C_Constraints().L_C_LineInCircle(geo5, geo4); //保存约束 ConstraintElement elem1 = new ConstraintElement(); elem1.strokeGroup1 = sg; elem1.strokeGroup2 = nd.strokeGroup; if (isL_C_Tangent) { elem1.ctype = ConstraintType.Tangent; sketch.m_pConsList.Add(elem1); // MessageBox.Show("Intersecting"); } if (isL_C_Intersect) { elem1.ctype = ConstraintType.Intersect; sketch.m_pConsList.Add(elem1); // MessageBox.Show("Parallel"); } if (isL_C_LineInCircle) { elem1.ctype = ConstraintType.In; sketch.m_pConsList.Add(elem1); // MessageBox.Show("Vertical"); } } break; case Graphic.Circle: //C_C break; default: break; } } } }
/// <summary> /// 向sketch中增加strokegroup /// </summary> /// <param name="strokegroup"></param> public void addGroup(StrokeGroup strokegroup) { groupList.Add(strokegroup); }