public void process(InkAnalyzer inkAnalyzer) { ContextNodeCollection contextNodeCollection = inkAnalyzer.FindLeafNodes(); List <Stroke> horizontalLines = InkUtils.findLines(contextNodeCollection); findAndDeleteStrikethrough(inkAnalyzer, canvas, horizontalLines, contextNodeCollection); }
/// <summary> /// Called when the StylusPoints on a Stroke are changed /// we use this to invalidate the stroke data in the analyzer /// </summary> private void OnStrokeStylusPointsChanged(object sender, EventArgs e) { Stroke changedStroke = (Stroke)sender; //a stroke's StylusPoints have changed we need to find //all affected contextNodes's and mark the dirty region with them StrokeCollection strokesThatChanged = new StrokeCollection(); strokesThatChanged.Add(changedStroke); ContextNodeCollection dirtyNodes = _inkAnalyzer.FindInkLeafNodes(strokesThatChanged); foreach (ContextNode dirtyNode in dirtyNodes) { //let the analyzer know that where the stroke previously //existed is now dirty _inkAnalyzer.DirtyRegion.Union(dirtyNode.Location.GetBounds()); } //let the analyzer know that the stroke data is no longer valid _inkAnalyzer.ClearStrokeData(changedStroke); //finally, make the region where the stroke now exists dirty also _inkAnalyzer.DirtyRegion.Union(changedStroke.GetBounds()); _inkAnalyzer.BackgroundAnalyze(); }
public void process(InkAnalyzer inkAnalyzer) { ContextNodeCollection contextNodeCollection = inkAnalyzer.FindLeafNodes(); List <Stroke> horizontalLines = InkUtils.findLines(contextNodeCollection); List <HeadingItem> headings = findHeadings(horizontalLines, contextNodeCollection); //Here is the end result of the headings mainHeading.headings = headings; //Invalidate and render the headings to the side panel mainHeading.invalidate(); }
/// <summary> /// Update each TextBox if analysis results exist for the corresponding hint /// </summary> private void UpdateTextBoxes() { // Get the hints that we previously added to the analyzer. ContextNodeCollection hints = this.analyzer.GetAnalysisHints(); for (int i = 0; i < hints.Count; i++) { // Get the recognized string from the hint string analyzedString = ((AnalysisHintNode)hints[i]).GetRecognizedString(); // If we found a string, set the contents of the TextBox // to that string. if (analyzedString != null) { this.textBoxes[i].Text = analyzedString; } } }
private void M_analizer_ResultsUpdated(object sender, ResultsUpdatedEventArgs e) { if (e.Status.Successful) { ContextNodeCollection leaves = ((InkAnalyzer)sender).FindLeafNodes(); foreach (ContextNode leaf in leaves) { if (leaf is InkWordNode) { // Como palabra InkWordNode t = leaf as InkWordNode; Rect l = t.Location.GetBounds(); ReconocerEntrada(t.GetRecognizedString()); } } LimpiarCanvas(); } }
public void process(InkAnalyzer inkAnalyzer) { ContextNodeCollection nodeCollection = inkAnalyzer.FindLeafNodes(); foreach (ContextNode childNodes in nodeCollection) { foreach (Stroke stroke in childNodes.Strokes) { if (strokeIsCaret(stroke)) { insertionBox.Visibility = Visibility.Visible; Canvas.SetLeft(insertionBox, stroke.StylusPoints[0].X - 140); Canvas.SetTop(insertionBox, stroke.StylusPoints[1].Y); inkAnalyzer.RemoveStroke(stroke); strokeToBeReplaced = stroke; } } } }
private void reflowAll(InkAnalyzer inkAnalyzer, InkCanvas inkCanvas) { ContextNodeCollection parentList = inkAnalyzer.RootNode.SubNodes; foreach (ContextNode node in parentList) { if (node is WritingRegionNode) { ContextNodeCollection paragraphs = node.SubNodes; foreach (ContextNode paragraph in paragraphs) { if (paragraph is ParagraphNode) { reflowParagraph(paragraph as ParagraphNode, inkAnalyzer, inkCanvas); } } } } }
private void M_analyzer_ResultsUpdated(object sender, ResultsUpdatedEventArgs e) { if (e.Status.Successful) { ContextNodeCollection leaves = ((InkAnalyzer)sender).FindLeafNodes(); foreach (ContextNode leaf in leaves) { if (leaf is InkWordNode) { // Como palabra InkWordNode t = leaf as InkWordNode; Rect l = t.Location.GetBounds(); var result = recognizer.EvaluateString(t.GetRecognizedString()); if (textResult != "") { if (textResult[textResult.Length - 1] == '?') { textResult = textResult.Replace("?", result); } else { textResult += result; } } else { textResult += result; } textBox.Text = textResult; } else { recognizer.MssgFeedback = "No se ha reconocido su trazo"; } FeedbackText.Text = recognizer.MssgFeedback; } //textBox.ScrollToEnd(); ResetCanvas(); } }
public static List <Stroke> findLines(ContextNodeCollection contextNodeCollection) { List <Stroke> horizontalLines = new List <Stroke>(); //Find single line gestures foreach (ContextNode node in contextNodeCollection) { if (node.Strokes.Count == 1) { Stroke stroke = node.Strokes[0]; if (strokeIsHorizontalLine(stroke)) { horizontalLines.Add(stroke); } } } //Find single line in words foreach (ContextNode node in contextNodeCollection) { if (node.Strokes.Count == 0) { continue; } if (node is InkWordNode) { InkWordNode word = node as InkWordNode; Rect bounds = word.Strokes.GetBounds(); foreach (Stroke stroke in word.Strokes) { if (stroke.GetBounds().Width / bounds.Width >= Constants.LINE_WORD_OVERLAPSE_RATIO) { horizontalLines.Add(stroke); } } } } return(horizontalLines); }
/// <summary> /// Analyze a new stroke. /// </summary> /// <param name="stroke"></param> /// <returns>true if the stroke was recognized as belonging to a graph (and so should be excluded from InkAnalyzer)</returns> public bool newStroke(Stroke stroke) { if (strokes.ContainsKey(stroke)) { // already have it! return(true); } foreach (Graph g in graphs) { if (g.containsStroke(stroke) && g.takeStroke(stroke)) { strokes.Add(stroke, g); return(true); } } Stroke copy = stroke.Clone(); analyzer.AddStroke(copy); analyzer.Analyze(); StrokeCollection sc = new StrokeCollection(new Stroke[] { copy }); ContextNodeCollection ctxNodes = analyzer.FindInkLeafNodes(sc); foreach (ContextNode ctxNode in ctxNodes) { if (ctxNode is InkDrawingNode && (ctxNode as InkDrawingNode).GetShapeName() == "Rectangle") { Graph g = new XYGraph(this, stroke); graphs.Add(g); strokes.Add(stroke, g); analyzer.RemoveStroke(copy); return(true); } } analyzer.RemoveStroke(copy); return(false); }
/// <summary> /// OnSelectionChanging raised when selection is changing on the InkAnalysisCanvas /// we use this to select entire nodes instead of just a stroke /// </summary> protected override void OnSelectionChanging(InkCanvasSelectionChangingEventArgs e) { StrokeCollection currentSelectedStrokes = e.GetSelectedStrokes(); if (currentSelectedStrokes.Count > 0) { ContextNodeCollection nodes = _inkAnalyzer.FindInkLeafNodes(e.GetSelectedStrokes()); if (nodes.Count > 0) { StrokeCollection expandedSelection = new StrokeCollection(); //add all related strokes if they aren't part of selectedStrokes already foreach (ContextNode node in nodes) { expandedSelection.Add(node.Strokes); } //modify the collection e.SetSelectedStrokes(expandedSelection); } } base.OnSelectionChanging(e); }
private void reflowParagraph(ParagraphNode node, InkAnalyzer inkAnalyzer, InkCanvas inkCanvas) { ContextNodeCollection lines = node.SubNodes; Rect bounds = node.Strokes.GetBounds(); List <InkWordNode> resultWords = new List <InkWordNode>(); double lineHeight = 0; double spacing = 30; //Collect all strokes foreach (ContextNode line in lines) { ContextNodeCollection words = line.SubNodes; foreach (ContextNode word in words) { lineHeight += word.Strokes.GetBounds().Height; InkWordNode wordNode = word as InkWordNode; resultWords.Add(wordNode); } } lineHeight /= resultWords.Count; List <List <InkWordNode> > resultLines = new List <List <InkWordNode> >(); List <double> lineMaxBaseline = new List <double>(); //Reflow strokes double x = 0; double maxX = inkCanvas.ActualWidth - bounds.X; resultLines.Add(new List <InkWordNode>()); lineMaxBaseline.Add(0); foreach (InkWordNode word in resultWords) { //Does word fit? Rect wordBound = word.Strokes.GetBounds(); if (x + wordBound.Width + spacing > maxX && multiline) { //Not fitting! Newline x = 0; resultLines.Add(new List <InkWordNode>()); lineMaxBaseline.Add(0); } x += spacing + wordBound.Width; PointCollection baseline = word.GetBaseline(); if (baseline != null && baseline.Count > 0) { double baselineFromTop = baseline[0].Y - wordBound.Y; resultLines[resultLines.Count - 1].Add(word); if (baselineFromTop > lineMaxBaseline[resultLines.Count - 1]) { lineMaxBaseline[resultLines.Count - 1] = baselineFromTop; } } } double y = 0; int lineNumber = 0; foreach (List <InkWordNode> line in resultLines) { double lineBaseline = lineMaxBaseline[lineNumber]; x = 0; foreach (InkWordNode word in line) { Rect wordBound = word.Strokes.GetBounds(); PointCollection baseline = word.GetBaseline(); double baselineFromTop = baseline[0].Y - wordBound.Y; double destX = (x + bounds.X); double dx = destX - (wordBound.X); //Match mid double dy = (y + lineBaseline + bounds.Y) - (wordBound.Y + baselineFromTop); InkUtils.transposeStrokes(inkAnalyzer, word.Strokes, dx, dy); x += spacing + wordBound.Width; } y += lineHeight + spacing; lineNumber++; } }
private void findAndDeleteStrikethrough(InkAnalyzer inkAnalyzer, InkCanvas canvas, List <Stroke> horizontalLines, ContextNodeCollection contextNodeCollection) { List <ContextNode> deletedNodes = new List <ContextNode>(); List <Stroke> removedHorizontalLines = new List <Stroke>(); //Find things to apply gestures to foreach (ContextNode node in contextNodeCollection) { if (node.Strokes.Count == 0) { continue; } Rect strikethroughBounds = node.Strokes.GetBounds(); strikethroughBounds.Height *= 0.75d; if (node is InkWordNode) { PointCollection bl = (node as InkWordNode).GetBaseline(); if (bl != null && bl.Count() > 0) { double baseline = bl[0].Y; strikethroughBounds.Height = baseline - strikethroughBounds.Y; } } for (int j = 0; j < horizontalLines.Count; j++) { if (node.Strokes[0] == horizontalLines[j]) { break; } Stroke horizontalLine = horizontalLines[j]; Rect horizontalLineBounds = horizontalLine.GetBounds(); double sideBuffer = (1 - Constants.LINE_WORD_OVERLAPSE_RATIO) / 2; double strikethroughBoundLeft = strikethroughBounds.X + strikethroughBounds.Width * sideBuffer; double strikethroughBoundRight = strikethroughBounds.X + strikethroughBounds.Width * (1 - sideBuffer); if (strikethroughBounds.IntersectsWith(horizontalLineBounds) && strikethroughBoundLeft > horizontalLineBounds.X && strikethroughBoundRight < horizontalLineBounds.X + horizontalLineBounds.Width) { //Delete strikethrough deletedNodes.Add(node); removedHorizontalLines.Add(horizontalLine); } } } foreach (Stroke stroke in removedHorizontalLines) { horizontalLines.Remove(stroke); canvas.Strokes.Remove(stroke); inkAnalyzer.RemoveStroke(stroke); } //Final step to apply the gestures, commit changes for (int i = deletedNodes.Count - 1; i >= 0; i--) { ContextNode node = deletedNodes[i]; try { Rect bounds = node.Strokes.GetBounds(); double nodeX = bounds.X; ContextNode parent = node.ParentNode; double closestX = double.MaxValue; foreach (ContextNode sibling in parent.SubNodes) { double siblingX = sibling.Strokes.GetBounds().X; if (siblingX > nodeX && siblingX < closestX) { closestX = siblingX; } } double dx = nodeX - closestX; foreach (ContextNode sibling in parent.SubNodes) { //Nodes right side of current if (sibling.Strokes.GetBounds().X > nodeX) { InkUtils.transposeStrokes(inkAnalyzer, sibling.Strokes, dx, 0d); } } canvas.Strokes.Remove(node.Strokes); inkAnalyzer.RemoveStrokes(node.Strokes); } catch (Exception e) { //Ignore already deleted error } } }
public static List<Stroke> findLines(ContextNodeCollection contextNodeCollection) { List<Stroke> horizontalLines = new List<Stroke>(); //Find single line gestures foreach (ContextNode node in contextNodeCollection) { if (node.Strokes.Count == 1) { Stroke stroke = node.Strokes[0]; if (strokeIsHorizontalLine(stroke)) { horizontalLines.Add(stroke); } } } //Find single line in words foreach (ContextNode node in contextNodeCollection) { if (node.Strokes.Count == 0) { continue; } if (node is InkWordNode) { InkWordNode word = node as InkWordNode; Rect bounds = word.Strokes.GetBounds(); foreach (Stroke stroke in word.Strokes) { if (stroke.GetBounds().Width / bounds.Width >= Constants.LINE_WORD_OVERLAPSE_RATIO) { horizontalLines.Add(stroke); } } } } return horizontalLines; }
private List <HeadingItem> findHeadings(List <Stroke> horizontalLines, ContextNodeCollection contextNodeCollection) { //Group lines together into "Heading Groups" List <HeadingItem> headings = new List <HeadingItem>(); foreach (Stroke node1 in horizontalLines) { List <HeadingItem> intersectHeadings = new List <HeadingItem>(); foreach (HeadingItem heading in headings) { bool intersectsAny = false; foreach (Stroke node2 in heading.lines) { Rect first = node1.GetBounds(); Rect second = node2.GetBounds(); if (Math.Abs(first.Y - second.Y) < Constants.HEADING_LINE_DISTANCE_MAX && Math.Abs(first.X - second.X) < Constants.HEADING_LINE_DISTANCE_MAX) { intersectsAny = true; break; } } if (intersectsAny) { intersectHeadings.Add(heading); } } HeadingItem resultHeading = new HeadingItem(); foreach (HeadingItem heading in intersectHeadings) { resultHeading.lines.AddRange(heading.lines); headings.Remove(heading); } resultHeading.lines.Add(node1); headings.Add(resultHeading); } //Find words that associate to Heading Groups foreach (ContextNode node in contextNodeCollection) { if (node.Strokes.Count == 0) { continue; } Rect underlineBounds = node.Strokes.GetBounds(); if (node is InkWordNode) { if ((node as InkWordNode).GetBaseline() != null && (node as InkWordNode).GetBaseline().Count > 0) { double baseline = (node as InkWordNode).GetBaseline()[0].Y; underlineBounds.Y = baseline; } InkWordNode word = node as InkWordNode; foreach (HeadingItem heading in headings) { if (heading.intersects(underlineBounds)) { heading.text.Add(word); break; } } } } //Remove bad headings List <HeadingItem> actualHeadings = new List <HeadingItem>(); foreach (HeadingItem heading in headings) { if (heading.text.Count > 0) { actualHeadings.Add(heading); } } return(actualHeadings); }
private List<HeadingItem> findHeadings(List<Stroke> horizontalLines, ContextNodeCollection contextNodeCollection) { //Group lines together into "Heading Groups" List<HeadingItem> headings = new List<HeadingItem>(); foreach (Stroke node1 in horizontalLines) { List<HeadingItem> intersectHeadings = new List<HeadingItem>(); foreach (HeadingItem heading in headings) { bool intersectsAny = false; foreach (Stroke node2 in heading.lines) { Rect first = node1.GetBounds(); Rect second = node2.GetBounds(); if (Math.Abs(first.Y - second.Y) < Constants.HEADING_LINE_DISTANCE_MAX && Math.Abs(first.X - second.X) < Constants.HEADING_LINE_DISTANCE_MAX) { intersectsAny = true; break; } } if (intersectsAny) { intersectHeadings.Add(heading); } } HeadingItem resultHeading = new HeadingItem(); foreach (HeadingItem heading in intersectHeadings) { resultHeading.lines.AddRange(heading.lines); headings.Remove(heading); } resultHeading.lines.Add(node1); headings.Add(resultHeading); } //Find words that associate to Heading Groups foreach (ContextNode node in contextNodeCollection) { if (node.Strokes.Count == 0) { continue; } Rect underlineBounds = node.Strokes.GetBounds(); if (node is InkWordNode) { if ((node as InkWordNode).GetBaseline() != null && (node as InkWordNode).GetBaseline().Count > 0) { double baseline = (node as InkWordNode).GetBaseline()[0].Y; underlineBounds.Y = baseline; } InkWordNode word = node as InkWordNode; foreach (HeadingItem heading in headings) { if (heading.intersects(underlineBounds)) { heading.text.Add(word); break; } } } } //Remove bad headings List<HeadingItem> actualHeadings = new List<HeadingItem>(); foreach (HeadingItem heading in headings) { if (heading.text.Count > 0) { actualHeadings.Add(heading); } } return actualHeadings; }
private void findAndDeleteStrikethrough(InkAnalyzer inkAnalyzer, InkCanvas canvas, List<Stroke> horizontalLines, ContextNodeCollection contextNodeCollection) { List<ContextNode> deletedNodes = new List<ContextNode>(); List<Stroke> removedHorizontalLines = new List<Stroke>(); //Find things to apply gestures to foreach (ContextNode node in contextNodeCollection) { if (node.Strokes.Count == 0) { continue; } Rect strikethroughBounds = node.Strokes.GetBounds(); strikethroughBounds.Height *= 0.75d; if (node is InkWordNode) { PointCollection bl = (node as InkWordNode).GetBaseline(); if (bl != null && bl.Count() > 0) { double baseline = bl[0].Y; strikethroughBounds.Height = baseline - strikethroughBounds.Y; } } for (int j = 0; j < horizontalLines.Count; j++) { if (node.Strokes[0] == horizontalLines[j]) { break; } Stroke horizontalLine = horizontalLines[j]; Rect horizontalLineBounds = horizontalLine.GetBounds(); double sideBuffer = (1 - Constants.LINE_WORD_OVERLAPSE_RATIO) / 2; double strikethroughBoundLeft = strikethroughBounds.X + strikethroughBounds.Width * sideBuffer; double strikethroughBoundRight = strikethroughBounds.X + strikethroughBounds.Width * (1 - sideBuffer); if (strikethroughBounds.IntersectsWith(horizontalLineBounds) && strikethroughBoundLeft > horizontalLineBounds.X && strikethroughBoundRight < horizontalLineBounds.X + horizontalLineBounds.Width) { //Delete strikethrough deletedNodes.Add(node); removedHorizontalLines.Add(horizontalLine); } } } foreach (Stroke stroke in removedHorizontalLines) { horizontalLines.Remove(stroke); canvas.Strokes.Remove(stroke); inkAnalyzer.RemoveStroke(stroke); } //Final step to apply the gestures, commit changes for (int i = deletedNodes.Count - 1; i >= 0; i--) { ContextNode node = deletedNodes[i]; try { Rect bounds = node.Strokes.GetBounds(); double nodeX = bounds.X; ContextNode parent = node.ParentNode; double closestX = double.MaxValue; foreach (ContextNode sibling in parent.SubNodes) { double siblingX = sibling.Strokes.GetBounds().X; if (siblingX > nodeX && siblingX < closestX) { closestX = siblingX; } } double dx = nodeX - closestX; foreach (ContextNode sibling in parent.SubNodes) { //Nodes right side of current if (sibling.Strokes.GetBounds().X > nodeX) { InkUtils.transposeStrokes(inkAnalyzer, sibling.Strokes, dx, 0d); } } canvas.Strokes.Remove(node.Strokes); inkAnalyzer.RemoveStrokes(node.Strokes); } catch (Exception e) { //Ignore already deleted error } } }