public bool RecognizeUseCase(Strokes inkStrokes) { if (inkStrokes.Count == 1) { StrokeInfo strokeInfo1 = new StrokeInfo(inkStrokes[0]); if (strokeInfo1.StrokeStatistics.StartEndProximity < CLOSED_PROXIMITY && strokeInfo1.StrokeStatistics.Square < 0.85 && strokeInfo1.StrokeStatistics.Diagonal > 0.13) return true; else return false; } else return false; }
/// <summary> /// Populates the stroke objects in an Ink Overlay object using the /// substrokes in a sketch object /// </summary> /// <param name="sketch">Sketch containing substrokes to convert</param> private void FillInkOverlay(Strokes strokes) { _OverlayInk.Ink.DeleteStrokes(); foreach (Stroke s in strokes) { _OverlayInk.Ink.CreateStroke(s.GetPoints()); } // Move center the ink's origin to the top-left corner Rectangle bb = _OverlayInk.Ink.GetBoundingBox(); _InkMovedX = 0.0f; _InkMovedY = 0.0f; _Scale = 1.0f; ScaleAndMoveInk(); this.InkPanel.Refresh(); }
private void UpdateStrokes() { App.Current.Dispatcher.Invoke(() => { // Do we need a lock here? IsRefreshingStrokes = true; var newStrokes = new StrokeCollection(StrokeCollection.GetMergedStrokeMaps()); Strokes.Clear(); Strokes.Add(newStrokes); if (EditingMode == InkCanvasEditingMode.Select) { SelectionChanged?.Invoke(SelectedStrokes); } IsRefreshingStrokes = false; }); }
protected override void OnStrokeCollected(InkCanvasStrokeCollectedEventArgs E) { void AddCustomStroke(Stroke CustomStroke) { Strokes.Remove(E.Stroke); // Remove two history items if (DataContext is ImageEditorViewModel vm) { vm.RemoveLastHistory(); vm.RemoveLastHistory(); } Strokes.Add(CustomStroke); var args = new InkCanvasStrokeCollectedEventArgs(CustomStroke); base.OnStrokeCollected(args); } switch (DynamicRenderer) { case LineDynamicRenderer _: AddCustomStroke(new Stroke(new StylusPointCollection(new [] { E.Stroke.StylusPoints.First(), E.Stroke.StylusPoints.Last() }), E.Stroke.DrawingAttributes)); break; case RectangleDynamicRenderer _: AddCustomStroke(new RectangleStroke(E.Stroke.StylusPoints, E.Stroke.DrawingAttributes)); break; case EllipseDynamicRenderer _: AddCustomStroke(new EllipseStroke(E.Stroke.StylusPoints, E.Stroke.DrawingAttributes)); break; default: base.OnStrokeCollected(E); break; } }
/// <summary> /// 清空 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void button2_Click(object sender, EventArgs e) { if (!ic.CollectingInk) { Strokes strokesToDelete = ic.Ink.Strokes; ic.Ink.DeleteStrokes(strokesToDelete); ic.Ink.DeleteStrokes(); //清除手写区域笔画; ink_here.Refresh(); //刷新手写区域 richTextBox1.Clear(); signPoints = new List <StylusPoint>(); strokes = new StrokeCollection(); strokeColl = new StylusPointCollection(); bpoint = new string[3] { "0", "0", "0" }; } }
/// <summary> /// Event Handle from Action->Clear menu. /// </summary> /// <param name="sender">The control that raised the event.</param> /// <param name="e">The event arguments.</param> private void miClear_Click(object sender, System.EventArgs e) { Strokes strokesToDelete = myInkCollector.Ink.Strokes; // Check to ensure that the ink collector isn't currently // in the middle of a stroke before clearing the ink. // Deleting a stroke that is currently being collected // will result in an error condition. if (!myInkCollector.CollectingInk) { myInkCollector.Ink.DeleteStrokes(strokesToDelete); miInk_Click(sender, e); } else { MessageBox.Show("Cannot clear ink while the ink collector is busy."); } }
private void hover_EditDeleteClicked(object sender, EventArgs e) { Strokes doomed = inkoverlay.Selection; if (doomed == null || doomed.Count != 1) { return; } // Simply delegate to the UI handler for deleting strokes. this.inkoverlay_StrokesDeleting(this, new InkOverlayStrokesDeletingEventArgs(doomed)); // Now, actually delete the strokes, too. doc.Ink.DeleteStrokes(doomed); // Clear the selection rectangle. inkoverlay.Selection = EmptyStrokes; }
public RTStroke(Guid documentIdentifier, Guid pageIdentifier, Stroke stroke, object extension) { DocumentIdentifier = documentIdentifier; PageIdentifier = pageIdentifier; Extension = extension; if (!stroke.ExtendedProperties.DoesPropertyExist(ExtendedPropertyStrokeIdentifier)) { stroke.ExtendedProperties.Add(ExtendedPropertyStrokeIdentifier, Guid.NewGuid().ToString()); } int[] strokeIds = new int[1]; strokeIds[0] = stroke.Id; Strokes ourStroke = stroke.Ink.CreateStrokes(strokeIds); Ink fromInk = stroke.Ink; ink = fromInk.ExtractStrokes(ourStroke, ExtractFlags.CopyFromOriginal); }
/// <summary> /// Event Handle from Paint event. It is necessary to handle the /// paint event since this sample needs to draw red points to indicate /// the strokes' cusps. /// </summary> /// <param name="sender">The control that raised the event.</param> /// <param name="e">The event arguments.</param> private void InkErase_OnPaint(object sender, PaintEventArgs e) { // Get the strokes to paint from the ink Strokes strokesToPaint = myInkCollector.Ink.Strokes; // Draw the strokes - note that it is necessary to manually // paint the strokes since auto-redrawing is set to false. myInkCollector.Renderer.Draw(e.Graphics, strokesToPaint); switch (mode) { case ApplicationMode.CuspErase: PaintCusps(e.Graphics, strokesToPaint); break; case ApplicationMode.IntersectErase: PaintIntersections(e.Graphics, strokesToPaint); break; } }
public override void TouchesEnded(NSSet touches, UIEvent evt) { base.TouchesEnded(touches, evt); if (!Enabled) { return; } var loc = (touches.AnyObject as UITouch).LocationInView(this); CurrentStroke.Points.Add(new Point(loc.X, loc.Y)); CurrentPathView.AddLineTo(loc); Strokes.Add(CurrentStroke); drawPath(); CurrentPathView.Clear(); SetNeedsDisplay(); }
private void btnRecognition_Click(object sender, EventArgs e) { string inkPadValue = ic.Ink.Strokes.ToString(); if (!ic.CollectingInk) { Strokes strokesToDelete = ic.Ink.Strokes; rct.StopBackgroundRecognition(); ic.Ink.DeleteStrokes(strokesToDelete); rct.Strokes = ic.Ink.Strokes; ic.Ink.DeleteStrokes();//清除手写区域笔画; PicInkPad.Refresh(); } InkWritingEventArgs ev = new InkWritingEventArgs(inkPadValue); if (UserHandWriting != null) { UserHandWriting(this, ev); } }
public DrawingRoomViewModel(Chat chat) { this.chat = chat; strokes = new StrokeCollection(); chat.OnStrokeRecieved += StrokeHandle; NewStrokeCommand = new RelayCommand(x => { var stroke = Strokes.LastOrDefault(); Strokes.Remove(stroke); chat.Send(stroke); //MessageBox.Show(stroke?.ToString()); }); InkCanvasDrawingAttributes = new DrawingAttributes(); InkCanvasDrawingAttributes.Color = Color.FromArgb(255, 0, 0, 0); InkCanvasDrawingAttributes.Height = 3; InkCanvasDrawingAttributes.Width = 3; OnPropertyChanged("InkCanvasDrawingAttributes"); }
private void HandleInkDeleting(object sender, StrokesEventArgs e) { using (Synchronizer.Lock(this.m_Ignore.SyncRoot)) { if (this.m_Ignore.Contains(e)) { this.m_Ignore.Remove(e); return; } } // Make a copy of the strokes that were removed. This must be done immediately // or the strokes _will_not_ exist by the time we need them. Strokes strokes = this.m_InkSheet.Ink.CreateStrokes(e.StrokeIds); SetStrokeIds(strokes); Ink ink = this.m_InkSheet.Ink.ExtractStrokes(strokes, ExtractFlags.CopyFromOriginal); this.m_EventQueue.Post(delegate() { this.m_HandleInkChangedDelegate(sender, ink.Strokes, false); }); }
private void DeleteInsideRectangle(Stroke s, Rectangle r, InkCollectorGestureEventArgs e) { // Se buscan los strokes que tengan al menos un 60% en el boundingbox Strokes borrarStrokes = ink_overlay.Ink.HitTest(r, 60); // Si se encuentra algo, se borran los strokes afectados if (borrarStrokes.Count > 0) { // El stroke del scratchout no se maneja mas e.Cancel = true; // Se borran los strokes afectados ink_overlay.Ink.DeleteStrokes(borrarStrokes); // Se borra el stroke del scratchout ink_overlay.Ink.DeleteStrokes(e.Strokes); Refresh(); } }
/// <summary> /// Helper method that performs a hit test using the specified point. /// It deletes all strokes that were hit by the point /// </summary> /// <param name="pt">The point to use for hit testing</param> private void EraseStrokes(Point pt, Stroke currentStroke) { // Use HitTest to find the collection of strokes that are intersected // by the point. The HitTestRadius constant is used to specify the // radius of the hit test circle in ink space coordinates (1 unit = .01mm). Strokes strokesHit = myInkCollector.Ink.HitTest(pt, HitTestRadius); if (null != currentStroke && strokesHit.Contains(currentStroke)) { strokesHit.Remove(currentStroke); } // Delete all strokes that were hit by the point myInkCollector.Ink.DeleteStrokes(strokesHit); if (strokesHit.Count > 0) { // Repaint the screen to reflect the change this.Refresh(); } }
private void hover_EditCloneClicked(object sender, EventArgs e) { Strokes selected = inkoverlay.Selection; if (selected == null || selected.Count != 1) { return; } // Get objects for the targeted stroke(s). Ensure that only one is selected. RigidBodyBase[] bodies = doc.GetBodiesFor(selected); if (bodies.Length != 1) { return; } RigidBodyBase body = bodies[0]; // First, clone the ink stroke. Move it down and to the right a bit. Rectangle newrect = selected.GetBoundingBox(); newrect.Offset(1000, 1000); doc.Ink.AddStrokesAtRectangle(selected, newrect); // Next, clone the body, binding it to the new stroke id. // Note: we got the new Strokes' ids by listening to the InkAdded event // AddStrokesAtRectangle doesn't return the strokes' ids. RigidBodyBase newbody = body.Clone(neweststrokeids[0]); doc.Bodies.Add(newbody); // Repaint the area around the newbody. Rectangle dirtybbox = newbody.BoundingBox; InvalidateInkSpaceRectangle(dirtybbox); // Select it, to show the smart tag. inkoverlay.Selection = doc.Ink.CreateStrokes(neweststrokeids); }
public bool RecognizeActor(Strokes inkStrokes) { if (inkStrokes.Count >= 4) { StrokeInfo strokeInfo1 = new StrokeInfo(inkStrokes[0]); StrokeInfo strokeInfo2 = new StrokeInfo(inkStrokes[1]); if (strokeInfo1.StrokeStatistics.StartEndProximity < CLOSED_PROXIMITY && strokeInfo1.StrokeStatistics.Square < 0.85 && strokeInfo1.StrokeStatistics.Diagonal > 0.15) { if (strokeInfo2.StrokeStatistics.StartEndProximity > CLOSED_PROXIMITY && strokeInfo2.StrokeStatistics.Square > 0.9 && strokeInfo2.StrokeStatistics.Diagonal < 0.2) return true; else return false; } else return false; } else return false; }
private List <GraphicsPath> InkToGraphicsPaths(bool scalePath) { Renderer renderer = _overlay.Renderer; Strokes strokes = _overlay.Ink.Strokes; float scaleX = _originalImage.Width / (float)pbImage.Width; float scaleY = _originalImage.Height / (float)pbImage.Height; if (strokes.Count > 0) { using (Graphics g = CreateGraphics()) { List <GraphicsPath> paths = new List <GraphicsPath>(strokes.Count); foreach (Stroke stroke in strokes) { Point[] points = stroke.GetPoints(); if (points.Length >= 3) { for (int i = 0; i < points.Length; i++) { renderer.InkSpaceToPixel(g, ref points[i]); if (scalePath) { points[i] = new Point( (int)(scaleX * points[i].X), (int)(scaleY * points[i].Y)); } } GraphicsPath path = new GraphicsPath(); path.AddPolygon(points); path.CloseFigure(); paths.Add(path); } } return(paths); } } return(null); }
/// <summary> /// Undo edit actions performed /// </summary> internal void Undo() { int index = undoActions.Count - 1; if (index < 0) { return; } if (undoActions[index] == InkCanvasEditingMode.Ink) { Strokes.RemoveAt(Strokes.Count - 1); } else if (undoActions[index] == InkCanvasEditingMode.EraseByStroke) { Strokes.Add(undoStrokes[index]); } else if (undoActions[index] == InkCanvasEditingMode.None) { for (int i = 0; i < index; i++) { if (undoActions[i] == InkCanvasEditingMode.Ink) { Strokes.Add(undoStrokes[i]); } else if (undoActions[i] == InkCanvasEditingMode.EraseByStroke) { Strokes.Remove(undoStrokes[i]); } else if (undoActions[i] == InkCanvasEditingMode.None) { Strokes.Clear(); } } } redoActions.Add(undoActions[index]); redoStrokes.Add(undoStrokes[index]); undoActions.RemoveAt(index); undoStrokes.RemoveAt(index); }
public static void ActualiceNonRecognizedStrokes() { Strokes stks = ink_overlay.Ink.Strokes; foreach (Stroke stk in stks) { bool processed = false; foreach (Stroke s in Facade.strokes_recognized) { if (CompareStrokes(stk, s)) { processed = true; } } if (!processed) { Facade.strokes_without_recognize.Add(stk); } } }
private void inkOverlay_StrokesDeleting(object sender, InkOverlayStrokesDeletingEventArgs e) { if (this.InvokeRequired) { return; } Strokes strokes = e.StrokesToDelete; //Remove the corresponding nodes and edges for each stroke for (int i = 0; i < strokes.Count; i++) { if (StrokeManager.isClosed(strokes[i], 0)) { graph.Remove(graph.Nodes.getNode(strokes[i])); } else { graph.Remove(graph.Edges.getEdge(strokes[i])); } } Invalidate(); }
protected override void OnStrokeCollected(InkCanvasStrokeCollectedEventArgs E) { void AddCustomStroke(Stroke CustomStroke) { Strokes.Remove(E.Stroke); Strokes.Add(CustomStroke); var args = new InkCanvasStrokeCollectedEventArgs(CustomStroke); base.OnStrokeCollected(args); } if (DynamicRenderer is IDynamicRenderer renderer) { AddCustomStroke(renderer.GetStroke(E.Stroke.StylusPoints, E.Stroke.DrawingAttributes)); } else { base.OnStrokeCollected(E); } }
private void inkOverlay_Stroke(object sender, InkCollectorStrokeEventArgs e) { Strokes strokes = null; Ink copiedInk = null; try { // Eraser strokes are transparent, we don't need to send them if (e.Stroke.DrawingAttributes.Transparency != 255) { // Give the stroke an identifier, so we can delete it remotely e.Stroke.ExtendedProperties.Add(StrokeIdentifier, Guid.NewGuid().ToString()); // Copy the stroke into its own Ink object, so that it can be serialized strokes = inkOverlay.Ink.CreateStrokes(new int[] { e.Stroke.Id }); copiedInk = e.Stroke.Ink.ExtractStrokes(strokes, ExtractFlags.CopyFromOriginal); // Send it across the network wb.SendObject(new SerializedInk(copiedInk)); } } catch (Exception ex) { Log(ex.ToString()); } finally { if (strokes != null) { strokes.Dispose(); } if (copiedInk != null) { copiedInk.Dispose(); } } }
public bool recognizePackage(Strokes inkStrokes) { if (inkStrokes.Count == 2) { StrokeInfo strokeInfo1 = new StrokeInfo(inkStrokes[0]); StrokeInfo strokeInfo2 = new StrokeInfo(inkStrokes[1]); if (strokeInfo1.StrokeStatistics.Square > 0.9 && strokeInfo1.StrokeStatistics.Diagonal < 0.09 && strokeInfo1.StrokeStatistics.StartEndProximity < CLOSED_PROXIMITY) { if (strokeInfo2.StrokeStatistics.Square > 0.9 && strokeInfo2.StrokeStatistics.Diagonal < 0.09) return true; else return false; } else { return false; } } else return false; }
/// <summary> /// Helper method to paint the stroke collection's intersections /// </summary> /// <param name="g">The graphics object to use for painting</param> /// <param name="strokesToPaint">The collection of strokes to paint</param> private void PaintIntersections(Graphics g, Strokes strokesToPaint) { // Draw the intersections of each stroke as little red circles foreach (Stroke currentStroke in strokesToPaint) { // Get the intersections of the stroke float[] intersections = currentStroke.FindIntersections(strokesToPaint); Point[] points = currentStroke.GetPoints(); // Draw each intersection in the stroke foreach (float fi in intersections) { // Get the point before the FINDEX Point ptIntersect = currentStroke.GetPoint((int)fi); // Find the fractional part of the FINDEX float fiFraction = fi - (int)fi; // if the fi does not have a fractional part, we have already // found the intersection point. Otherwise, use the FINDEX to // calculate the interpolated intersection point on the stroke if (fiFraction > 0.0f) { Point ptNextIntersect = currentStroke.GetPoint((int)fi + 1); ptIntersect.X += (int)((ptNextIntersect.X - ptIntersect.X) * fiFraction); ptIntersect.Y += (int)((ptNextIntersect.Y - ptIntersect.Y) * fiFraction); } // Convert the X, Y position to Window based pixel coordinates myInkCollector.Renderer.InkSpaceToPixel(g, ref ptIntersect); // Draw a red circle as the intersection position g.DrawEllipse(Pens.Red, ptIntersect.X - 3, ptIntersect.Y - 3, 6, 6); } } }
/// <summary> /// Helper method to paint the stroke collection's cusps /// </summary> /// <param name="g">The graphics object to use for painting</param> /// <param name="strokesToPaint">The collection of strokes to paint</param> private void PaintCusps(Graphics g, Strokes strokesToPaint) { // now draw PolylineCusp points foreach (Stroke currentStroke in strokesToPaint) { // Retrieve the cusps of the stroke. The cusps mark the points where // the stroke changes direction abruptly. A segment is defined as the // points between two cusps. int[] cusps = currentStroke.PolylineCusps; // Draw each cusp in the stroke foreach (int i in cusps) { // Get the X, Y position of the cusp Point pt = currentStroke.GetPoint(i); // Convert the X, Y position to Window based pixel coordinates myInkCollector.Renderer.InkSpaceToPixel(g, ref pt); // Draw a red circle as the cusp position g.DrawEllipse(Pens.Red, pt.X - 3, pt.Y - 3, 6, 6); } } }
/// <summary> /// obtains and returns alternative recognition results /// </summary> /// <param name="strokes">the strokes to be recognized</param> /// <returns>list of alternative</returns> private RecognitionAlternates getAlternative(Strokes strokes) { try { RecognizerContext context = new RecognizerContext(); context.Strokes = strokes; RecognitionStatus status; RecognitionResult result = context.Recognize(out status); RecognitionAlternates ra; if (RecognitionStatus.NoError == status) { ra = result.GetAlternatesFromSelection(); } else { ra = null; } return(ra); } catch (Exception) { return(null); } }
/// <summary> /// /// </summary> /// <param name="strokes"></param> internal String recognize(Strokes strokes, out RecognitionAlternates alternates) { RecognizerContext rc = new RecognizerContext(); rc.Strokes = strokes; try { RecognitionStatus status; RecognitionResult result; result = rc.Recognize(out status); if (status == RecognitionStatus.NoError) { RecognitionAlternates alternatives = result.GetAlternatesFromSelection(); alternates = alternatives; return result.TopString; } else { Console.WriteLine("Error in recognition."); } } catch { Console.WriteLine("Exception in recognition."); } alternates = null; return null; }
public Recognition(Strokes s, string _allograph, int baseline, int midpt, bool msftRecog) { _strokes = s; _bbox = s.GetBoundingBox(); updateIds(); allograph = _allograph; _curalt = 0; Result[] tmpalts; if (_allographToAlternates.TryGetValue(allograph + (msftRecog?"MSFT":""), out tmpalts)) { alts = (Result[])tmpalts.Clone(); } else if (_allograph.Length == 1) { alts = new Result[] { new Result(_allograph[0]) }; } else { alts = new Result[] { new Result(_allograph) }; } for (int i = 0; i < alts.Length; i++) { alts[i] = new Result(alts[i]); } baselinealts = new int[alts.Length]; xheightalts = new int[alts.Length]; levelsetby = int.MaxValue; msftRecoged = msftRecog; for (int i = 0; i < alts.Length; i++) { SetMetrics(alts[i] == Result.Special.Imaginary ? "i" : alts[i], // bcz: Hack! need to do something similar for 'e' etc? baseline, midpt, ref baselinealts[i], ref xheightalts[i]); } }
private void hover_EditPropertiesClicked(object sender, EventArgs e) { Strokes selected = inkoverlay.Selection; if (selected == null || selected.Count != 1) { return; } // Get objects for the targeted stroke(s). Ensure that only one is selected. RigidBodyBase[] bodies = doc.GetBodiesFor(selected); if (bodies.Length != 1) { return; } RigidBodyBase body = bodies[0]; using (BodyPropertiesForm bpf = new BodyPropertiesForm(body)) { bpf.ShowDialog(this); Invalidate(); } }
/// <summary> /// Initializes a new instance of the <see cref="WritingRecognition"/> class. /// </summary> /// <param name="control">The control.</param> /// <param name="culture">The culture.</param> public WritingRecognition(Control control, CultureInfo culture) { foreach (Recognizer reco in _recognizers) for (int c = 0; c < reco.Languages.Length; c++) if (reco.Languages[c] == culture.LCID) { _context = reco.CreateRecognizerContext(); break; } if (_context == null) { MessageBox.Show(culture.DisplayName + " handwriting recognition support isn't installed on this Windows.", "Rincevent", MessageBoxButtons.OK, MessageBoxIcon.Hand); return; } _inkOverlay = new InkOverlay(control, true); _inkOverlay.Enabled = true; _strokes = _inkOverlay.Ink.CreateStrokes(); _context.Strokes = _strokes; _inkOverlay.Stroke += inkOverlay_Stroke; _inkOverlay.DefaultDrawingAttributes.AntiAliased = true; _inkOverlay.DefaultDrawingAttributes.Color = Color.DarkViolet; _inkOverlay.DefaultDrawingAttributes.FitToCurve = true; _context.RecognitionWithAlternates += context_RecognitionWithAlternates; }
internal RigidBodyBase[] GetBodiesFor(Strokes strokes) { ArrayList list = new ArrayList(); foreach (Stroke s in strokes) { foreach (RigidBodyBase body in Bodies) { if (body.strokeid == s.Id) list.Add(body); } } return list.ToArray(typeof(RigidBodyBase)) as RigidBodyBase[]; }
//Gets the edges corresponding to the given strokes public Edges getEdges(Strokes strokes) { Edges found = new Edges(); for(int i=0; i<strokes.Count; i++) { Edge e = getEdge(strokes[i]); if(e != null) { found.Add(e); } } return found; }
private void HandleInkChanged(object sender, Strokes changed, bool adding) { using(Synchronizer.Lock(this.Undo.SyncRoot)) { // Create an IUndoer that will re-add or re-delete the copied strokes. IUndoer undoer = new InkUndoer(this, changed, adding); this.Undo.Push(undoer); } }
// --------------- Form Events --------------- /// <summary> /// Event Handler from Form Load Event /// Setup the ink collector for collection /// </summary> /// <param name="sender">The control that raised the event.</param> /// <param name="e">The event arguments.</param> private void InkClipboard_Load(object sender, System.EventArgs e) { // Set the application mode to inking applicationMode = ApplicationMode.Ink; // Initialize the selection data lassoPoints = new ArrayList(); selectionHandles = new PictureBox[] {leftTopHandle,centerTopHandle,rightTopHandle,leftCenterHandle,rightCenterHandle,leftBottomHandle,centerBottomHandle,rightBottomHandle}; selectionRect = new Rectangle(); selectedStrokes = null; // Create the pens used to draw the lasso selection connectorPen = new Pen(connectorColor); // Pen used to draw dotted lasso connector line connectorPen.DashStyle = DashStyle.Dash; dotEdgePen = new Pen(dotEdgeColor); // Pen used to draw the outer edge of the lasso dot dotPen = new Pen(dotColor); // Pen used to draw the center of the lasso dot // Create a new ink collector and assign it to this form's window myInkCollector = new InkCollector(this.Handle); // Set the ink collector's pen width myInkCollector.DefaultDrawingAttributes.Width = MediumInkWidth; // Turn the ink collector on myInkCollector.Enabled = true; }
private void UpdateAndSetStrokesToRemoveIds(Strokes strokes) { using (Synchronizer.Lock(this.m_Watcher.m_InkSheet.Ink.Strokes.SyncRoot)) { Debug.Assert(this.m_StrokesToRemove == null); string[] ids = new string[strokes.Count]; for (int i = 0; i < ids.Length; i++) { Stroke stroke = strokes[i]; Debug.Assert(stroke.ExtendedProperties.DoesPropertyExist(StrokeIdExtendedProperty)); ids[i] = ((string)stroke.ExtendedProperties[StrokeIdExtendedProperty].Data); } this.m_StrokesToRemove = ids; } }
public void addStroke(Stroke stroke) { Strokes.Add(stroke); }
/// <summary> /// Helper method to paint the stroke collection's cusps /// </summary> /// <param name="g">The graphics object to use for painting</param> /// <param name="strokesToPaint">The collection of strokes to paint</param> private void PaintCusps(Graphics g, Strokes strokesToPaint) { // now draw PolylineCusp points foreach (Stroke currentStroke in strokesToPaint) { // Retrieve the cusps of the stroke. The cusps mark the points where // the stroke changes direction abruptly. A segment is defined as the // points between two cusps. int[] cusps = currentStroke.PolylineCusps; // Draw each cusp in the stroke foreach (int i in cusps) { // Get the X, Y position of the cusp Point pt = currentStroke.GetPoint(i); // Convert the X, Y position to Window based pixel coordinates myInkCollector.Renderer.InkSpaceToPixel(g, ref pt); // Draw a red circle as the cusp position g.DrawEllipse(Pens.Red, pt.X-3, pt.Y-3, 6, 6); } } }
private void inkoverlay_StrokesDeleting(object sender, InkOverlayStrokesDeletingEventArgs e) { dbg.WriteLine("----- inkoverlay_StrokesDeleting -----"); // Ensure we're on the UI thread. dbg.Assert(!this.InvokeRequired); // Track region to repaint. Rectangle dirtybbox = Rectangle.Empty; try // To prevent exceptions from propagating back to ink runtime. { // Get objects for stroke(s) to delete. RigidBodyBase[] bodies = doc.GetBodiesFor(e.StrokesToDelete); MechanismBase[] mechs = doc.GetMechanismsFor(e.StrokesToDelete); // Delete mechanisms. foreach (MechanismBase mech in mechs) { doc.Mechanisms.Remove(mech); dirtybbox = Rectangle.Union(dirtybbox, mech.BoundingBox); } // Delete bodies and their attached mechanisms. foreach (RigidBodyBase body in bodies) { mechs = doc.GetMechanismsForBody(body); foreach (MechanismBase mech in mechs) { doc.Mechanisms.Remove(mech); dirtybbox = Rectangle.Union(dirtybbox, mech.BoundingBox); Strokes mstrokes = doc.Ink.CreateStrokes(new int[] { mech.strokeid }); doc.Ink.DeleteStrokes(mstrokes); } doc.Bodies.Remove(body); dirtybbox = Rectangle.Union(dirtybbox, body.BoundingBox); } // Check if this stroke was the gravity vector's? if (doc.Gravity != null) { foreach (Stroke s in e.StrokesToDelete) { if (s.Id == doc.Gravity.strokeid) { this.InvalidateInkSpaceRectangle(doc.Gravity.BoundingBox); doc.Gravity = null; } } } } catch (Exception ex) { // Log the error. Global.HandleThreadException(this, new System.Threading.ThreadExceptionEventArgs(ex)); } finally { // Repaint the affected area. InvalidateInkSpaceRectangle(dirtybbox); } }
public InkUndoer(InkSheetUndoService watcher, Strokes strokes, bool adding) { this.m_Watcher = watcher; if(adding) { this.UpdateAndSetStrokesToRemoveIds(strokes); } else { this.m_StrokesToAdd = strokes; } this.m_Adding = adding; }
private void AddInk() { using(Synchronizer.Lock(this)) { // Create an array of stroke Ids in order to fire the InkAdded event later. int[] ids = new int[this.m_StrokesToAdd.Count]; using (Synchronizer.Lock(this.m_Watcher.m_InkSheet.Ink.Strokes.SyncRoot)) { for (int i = 0; i < ids.Length; i++) { Stroke stroke = this.m_StrokesToAdd[i]; // The stroke probably has no association with the current Ink object. // Therefore, we have to recreate it by copying the raw packet data. // This first requires recreating the TabletPropertyDescriptionCollection, // which, for some stupid reason, must be done manually for lack of a better API. TabletPropertyDescriptionCollection properties = new TabletPropertyDescriptionCollection(); foreach (Guid property in stroke.PacketDescription) properties.Add(new TabletPropertyDescription(property, stroke.GetPacketDescriptionPropertyMetrics(property))); // Create a new stroke from the raw packet data. Stroke created = this.m_Watcher.m_InkSheet.Ink.CreateStroke(stroke.GetPacketData(), properties); // Copy the DrawingAttributes and all application data // (especially the StrokesIdExtendedProperty) to the new stroke. created.DrawingAttributes = stroke.DrawingAttributes; foreach (ExtendedProperty prop in stroke.ExtendedProperties) created.ExtendedProperties.Add(prop.Id, prop.Data); // Get the new stroke's Id so we can fire the InkAdded event. ids[i] = created.Id; } // If the added strokes don't yet have StrokeIdExtendedProperty properties, // create new Guids for them. Regardless, set this.m_StrokesToRemove // to the list of stroke Guids. this.UpdateAndSetStrokesToRemoveIds(this.m_StrokesToAdd); // Then, unset this.m_StrokesToAdd since they're already added. this.m_StrokesToAdd = null; } // Create the event arguments and add them to the ignore list so the // InkSheetUndoService won't create an InkUndoer for this change. StrokesEventArgs args = new StrokesEventArgs(ids); using(Synchronizer.Lock(this.m_Watcher.m_Ignore.SyncRoot)) { this.m_Watcher.m_Ignore.Add(args); } // Finally fire the appropriate InkAdded event from the InkSheetModel. this.m_Watcher.m_InkSheet.OnInkAdded(args); } }
void OnPreviewMouseDown(object sender, MouseButtonEventArgs e) { canvas !.Strokes.Clear(); Element.Points.Clear(); }
private void RemoveInk() { using (Synchronizer.Lock(this)) { // Collect all of the strokes we're supposed to delete. using (Synchronizer.Lock(this.m_Watcher.m_InkSheet.Ink.Strokes.SyncRoot)) { Strokes deleting = this.m_Watcher.m_InkSheet.Ink.CreateStrokes(); foreach (Stroke stroke in this.m_Watcher.m_InkSheet.Ink.Strokes) if (stroke.ExtendedProperties.DoesPropertyExist(StrokeIdExtendedProperty)) if (Array.IndexOf(this.m_StrokesToRemove, stroke.ExtendedProperties[StrokeIdExtendedProperty].Data) >= 0) deleting.Add(stroke); // It's possible that some of the strokes have been deleted elsewhere. // But this shouldn't happen because doing so should have caused an InkUndoer to be // pushed onto the Undo stack. So, for now, this check is "merely" a Debug.Assert. // TODO: Decide whether this should be an error, or at least whether it should // invalidate the rest of the undo stack. Debug.Assert(deleting.Count == this.m_StrokesToRemove.Length); // Get the stroke Ids so we can make a copy of the ink and fire the OnDeleting and OnDeleted events. int[] ids = new int[deleting.Count]; for (int i = 0; i < ids.Length; i++) // Is there a better way to get the array of Ids? ids[i] = deleting[i].Id; // Make a copy of the strokes, because if the original ink is later deleted // from the Ink object then it will become unusable. Ink ink = this.m_Watcher.m_InkSheet.Ink.ExtractStrokes(deleting, ExtractFlags.CopyFromOriginal); this.m_StrokesToAdd = ink.Strokes; this.m_StrokesToRemove = null; // Create the event arguments and add them to the ignore list so the // InkSheetUndoService won't create an InkUndoer for this change. StrokesEventArgs args = new StrokesEventArgs(ids); using (Synchronizer.Lock(this.m_Watcher.m_Ignore.SyncRoot)) { this.m_Watcher.m_Ignore.Add(args); } // Actually delete the ink, firing the appropriate events on the InkSheetModel. this.m_Watcher.m_InkSheet.OnInkDeleting(args); this.m_Watcher.m_InkSheet.Ink.DeleteStrokes(deleting); this.m_Watcher.m_InkSheet.OnInkDeleted(args); } } }
protected override void OnElementChanged(ElementChangedEventArgs <DrawingView> e) { base.OnElementChanged(e); if (Control == null && Element != null) { canvas = new InkCanvas { Background = Element.BackgroundColor.ToBrush(), DefaultDrawingAttributes = new() { Color = Element.DefaultLineColor.ToMediaColor(), Width = Element.DefaultLineWidth, Height = Element.DefaultLineWidth } }; Element.Lines.CollectionChanged += OnCollectionChanged; SetNativeControl(canvas); canvas.Strokes.StrokesChanged += OnStrokesChanged; Control !.PreviewMouseDown += OnPreviewMouseDown; } if (e.OldElement != null) { canvas !.Strokes.StrokesChanged -= OnStrokesChanged; Element !.Lines.CollectionChanged -= OnCollectionChanged; if (Control != null) { Control.PreviewMouseDown -= OnPreviewMouseDown; } } } void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs args) { canvas !.Strokes.StrokesChanged -= OnStrokesChanged; canvas.Strokes.Clear(); LoadLines(); canvas.Strokes.StrokesChanged += OnStrokesChanged; } void OnPreviewMouseDown(object sender, MouseButtonEventArgs e) => Clear(); void Clear(bool force = false) { if (!Element.MultiLineMode || force) { canvas !.Strokes.Clear(); Element.Lines.Clear(); } } void OnStrokesChanged(object sender, StrokeCollectionChangedEventArgs e) { Element.Lines.CollectionChanged -= OnCollectionChanged; if (e.Added.Count > 0) { if (!Element.MultiLineMode) { Element.Lines.Clear(); } var lines = Element.MultiLineMode ? e.Added : new StrokeCollection() { e.Added.First() }; foreach (var line in lines) { var points = line.StylusPoints.Select(point => new Point(point.X, point.Y)).ToList(); Element.Lines.Add(new Line() { Points = new ObservableCollection <Point>(points), LineColor = Color.FromRgba(line.DrawingAttributes.Color.R, line.DrawingAttributes.Color.G, line.DrawingAttributes.Color.B, line.DrawingAttributes.Color.A), LineWidth = (float)line.DrawingAttributes.Width }); } if (Element.Lines.Count > 0) { var lastLine = Element.Lines.Last(); if (Element.DrawingLineCompletedCommand?.CanExecute(lastLine) ?? false) { Element.DrawingLineCompletedCommand.Execute(lastLine); } } if (Element.ClearOnFinish) { Element.Lines.CollectionChanged -= OnCollectionChanged; Clear(true); canvas !.Strokes.StrokesChanged += OnStrokesChanged; } } Element.Lines.CollectionChanged += OnCollectionChanged; } void LoadLines() { var lines = Element.MultiLineMode ? Element.Lines : Element.Lines.Any() ? new ObservableCollection <Line> { Element.Lines.LastOrDefault() } : new ObservableCollection <Line>(); foreach (var line in lines) { var stylusPoints = line.Points.Select(point => new StylusPoint(point.X, point.Y)).ToList(); if (stylusPoints is { Count: > 0 }) { var stroke = new Stroke(new StylusPointCollection(stylusPoints)) { DrawingAttributes = new() { Color = line.LineColor.ToMediaColor(), Width = line.LineWidth, Height = line.LineWidth } }; canvas !.Strokes.Add(stroke); } } }
/// <summary> /// Helper method to paint the stroke collection's intersections /// </summary> /// <param name="g">The graphics object to use for painting</param> /// <param name="strokesToPaint">The collection of strokes to paint</param> private void PaintIntersections(Graphics g, Strokes strokesToPaint) { // Draw the intersections of each stroke as little red circles foreach (Stroke currentStroke in strokesToPaint) { // Get the intersections of the stroke float[] intersections = currentStroke.FindIntersections(strokesToPaint); Point[] points = currentStroke.GetPoints(); // Draw each intersection in the stroke foreach (float fi in intersections) { // Get the point before the FINDEX Point ptIntersect = currentStroke.GetPoint((int)fi); // Find the fractional part of the FINDEX float fiFraction = fi - (int)fi; // if the fi does not have a fractional part, we have already // found the intersection point. Otherwise, use the FINDEX to // calculate the interpolated intersection point on the stroke if (fiFraction > 0.0f) { Point ptNextIntersect = currentStroke.GetPoint((int)fi + 1); ptIntersect.X += (int)((ptNextIntersect.X - ptIntersect.X) * fiFraction); ptIntersect.Y += (int)((ptNextIntersect.Y - ptIntersect.Y) * fiFraction); } // Convert the X, Y position to Window based pixel coordinates myInkCollector.Renderer.InkSpaceToPixel(g, ref ptIntersect); // Draw a red circle as the intersection position g.DrawEllipse(Pens.Red, ptIntersect.X-3, ptIntersect.Y-3, 6, 6); } } }
//Get the nodes corresponding to the following strokes public Nodes getNodes(Strokes strokes) { Nodes found = new Nodes(); for(int i=0; i<strokes.Count; i++) { Node a = getNode(strokes[i]); if(a != null) { found.Add(a); } } return found; }
/// <summary> /// Sets the selected strokes and selection rectangle. /// </summary> /// <param name="strokes">The strokes that should be selected. If null, the selection becomes empty</param> private void SetSelection(Strokes strokes) { // Tracks whether the rectangle that bounds the selected // strokes should be displayed bool isSelectionVisible = false; // Update the selected strokes collection selectedStrokes = strokes; // If no strokes are selected, set the selection rectangle // to empty if (!HasSelection()) { selectionRect = Rectangle.Empty; } // Otherwise, at least one stroke is selected and it is necessary // to display the selection rectangle. else { isSelectionVisible = true; // Retrieve the bounding box of the strokes selectionRect = selectedStrokes.GetBoundingBox(); using (Graphics g = CreateGraphics()) { InkSpaceToPixel(g, ref selectionRect); } // Pad the selection rectangle so that the selected ink // doesn't overlap with the selection rectangle's handles. selectionRect.Inflate(SelectionRectBuffer, SelectionRectBuffer); // compute the center of the rectangle that bounds the // selected strokes int xAvg = (selectionRect.Right+selectionRect.Left)/2; int yAvg = (selectionRect.Top+selectionRect.Bottom)/2; // Draw the resize handles // top left SetLocation(selectionHandles[0],selectionRect.Left, selectionRect.Top); // top SetLocation(selectionHandles[1],xAvg, selectionRect.Top); // top right SetLocation(selectionHandles[2],selectionRect.Right, selectionRect.Top); // left SetLocation(selectionHandles[3],selectionRect.Left, yAvg); // right SetLocation(selectionHandles[4],selectionRect.Right, yAvg); // bottom left SetLocation(selectionHandles[5],selectionRect.Left, selectionRect.Bottom); // bottom SetLocation(selectionHandles[6],xAvg, selectionRect.Bottom); // bottom right SetLocation(selectionHandles[7],selectionRect.Right, selectionRect.Bottom); } // Set the visibility of each selection handle in the // selection rectangle. If there is no selection, all // handles should be hidden. Otherwise, all handles should // be visible. foreach(PictureBox pb in selectionHandles) { pb.Visible = isSelectionVisible; } // Turn off autoredrawing if there is a selection - otherwise, // the selected ink will not be displayed as selected. myInkCollector.AutoRedraw = !isSelectionVisible; // Since the selection has changed, repaint the screen. Refresh(); }
internal MechanismBase[] GetMechanismsFor(Strokes strokes) { ArrayList list = new ArrayList(); foreach (Stroke s in strokes) { foreach (MechanismBase mech in Mechanisms) { if (mech.strokeid == s.Id) list.Add(mech); } } return list.ToArray(typeof(MechanismBase)) as MechanismBase[]; }
private static void SetStrokeIds(Strokes strokes) { foreach(Stroke stroke in strokes) if(!stroke.ExtendedProperties.DoesPropertyExist(StrokeIdExtendedProperty)) stroke.ExtendedProperties.Add(StrokeIdExtendedProperty, Guid.NewGuid().ToString()); }