/// <summary> /// Split both a Microsoft and Converter stroke at indices and add them to the docmunte /// </summary> /// <param name="id">The id of the Microsoft and Converter stroke</param> /// <param name="indices">The indices to split at</param> /// <param name="document">The document to add to</param> public void splitStrokes(int id, float[] indices, MakeXML document) { Microsoft.Ink.Stroke mStroke = this.getMStrokeById(id); Stroke cStroke = (Stroke)this.idToCStroke[id]; this.splitStrokes(mStroke, cStroke, indices, document); }
/// <summary> /// Split both a Microsoft and Converter stroke /// </summary> /// <param name="mStroke">The Microsoft stroke</param> /// <param name="cStroke">The Converter stroke</param> /// <param name="indices">The indices to split at</param> /// <param name="document">The document</param> private void splitStrokes(Microsoft.Ink.Stroke mStroke, Stroke cStroke, float[] indices, MakeXML document) { int id = mStroke.Id; //We can only split two of the same strokes... they must be in the hashtable as such if (this.idToCStroke.ContainsKey(id) && this.getMStrokeById(id) != null) { //Remove the stroke from the hashtable (this may work below the splitting up code) //this.mStrokeToCStroke.Remove(mStroke); this.idToCStroke.Remove(id); //Get the corresponding splitted strokes //The should line up Microsoft.Ink.Stroke[] mStrokes = splitMStroke(mStroke, indices); Stroke[] cStrokes = splitCStroke(cStroke, indices); //Create the updated mapping for (int i = 0; i < mStrokes.Length; ++i) { int sId = mStrokes[i].Id; this.idToCStroke.Add(sId, cStrokes[i]); document.addShape(cStrokes[i]); } } else { object i = "test"; int b = (int)i; //Error halt here } }
/// <summary> /// Receive stroke for Presenter 1. /// </summary> /// <param name="bc"></param> private void ReceiveStroke(BufferChunk bc) { BinaryFormatter formatter = new BinaryFormatter(); MemoryStream memoryStream = new MemoryStream(bc.Buffer, 1, bc.Length - 1); int slideIndex = (int)formatter.Deserialize(memoryStream); if (this.SlideDeck != null && slideIndex >= 0) { InkScribble s = (InkScribble)this.SlideDeck.GetOverlay(slideIndex).Scribble; // Restore the bytes to ink. byte[] bytes = new byte[memoryStream.Length - memoryStream.Position]; memoryStream.Read(bytes, 0, bytes.Length); Ink.Ink ink = new Ink.Ink(); ink.Load(bytes); // Delete the previous version of this stroke if necessary. foreach (Ink.Stroke stroke in ink.Strokes) { if (stroke.ExtendedProperties.DoesPropertyExist(GUID_TAG)) { Ink.Stroke foundStroke; bool found = FastFindStrokeFromGuid(s, new Guid((string)stroke.ExtendedProperties[GUID_TAG].Data), out foundStroke, GUID_TAG); if (found) { s.Ink.DeleteStroke(foundStroke); } } } lock (this) { Rectangle r = ink.Strokes.GetBoundingBox(); r.X = (int)(r.X * XinkScaleFactor); r.Y = (int)(r.Y * YinkScaleFactor); r.Width = (int)(r.Width * XinkScaleFactor); r.Height = (int)(r.Height * YinkScaleFactor); s.Ink.AddStrokesAtRectangle(ink.Strokes, r); // Make note of the ink's strokes in the guidtable. // ASSUME that these strokes went on the end. int sCount = s.Ink.Strokes.Count; int newCount = ink.Strokes.Count; for (int i = sCount - newCount; i < sCount; i++) { Ink.Stroke stroke = s.Ink.Strokes[i]; if (stroke.ExtendedProperties.Contains(GUID_TAG)) { Guid guid = new Guid((string)stroke.ExtendedProperties[GUID_TAG].Data); this.myGuidTable[new ScribbleIntPair(s, stroke.Id)] = guid; this.myGuidReverseTable[guid] = new ScribbleIntPair(s, stroke.Id); } } } } }
private void menuStrokeInformation_Click(object sender, EventArgs e) { Sketch.Sketch sketch = sketchPanel.Sketch; FeatureSketch sketchFeatures = new FeatureSketch(ref sketch); Microsoft.Ink.Strokes selected = sketchPanel.InkSketch.Ink.Strokes; Microsoft.Ink.Stroke s = selected[selected.Count - 1]; Sketch.Substroke ss = sketchPanel.InkSketch.GetSketchSubstrokeByInkId(s.Id); StrokeInfoForm.strokeInfoForm sif = new StrokeInfoForm.strokeInfoForm(sketchFeatures.GetFeatureStrokeByStrokeGUID(ss.Id), sketchFeatures, s, ss); sif.Show(); }
/// <summary> /// Find Stroke from Guid /// </summary> /// The original version was much too slow for the archive replay scenario. /// <param name="scribble"></param> /// <param name="guid"></param> /// <param name="stroke"></param> /// <param name="guidTag"></param> /// <returns></returns> private bool FastFindStrokeFromGuid(InkScribble scribble, Guid guid, out Ink.Stroke stroke, Guid guidTag) { Ink.Ink ink = scribble.Ink; if (this.myGuidReverseTable.Contains(guid)) { if (((ScribbleIntPair)this.myGuidReverseTable[guid]).scribble == scribble) { ScribbleIntPair pair = (ScribbleIntPair)this.myGuidReverseTable[guid]; /// The count can be zero right after a clear slide or clear deck operation /// if count is zero, CreateStrokes will except. if (pair.scribble.Count == 0) { stroke = null; return(false); } Ink.Strokes targetStrokes = null; try { targetStrokes = ink.CreateStrokes(new int[] { pair.id }); } catch (Exception e) { //not clear when this would happen? stroke = null; Trace.WriteLine("FastFindStrokeFromGuid: Exception during CreateStrokes: " + e.ToString()); return(false); } if (targetStrokes.Count < 1) //not clear when this would happen? { stroke = null; Trace.WriteLine("FastFindStrokeFromGuid: Found target with zero stroke count."); return(false); } // Found it. stroke = targetStrokes[0]; return(true); } else { //This happens when we revisit slides we've been on previously this.myGuidReverseTable.Remove(guid); stroke = null; return(false); } } else { stroke = null; return(false); } }
/// <summary> /// Given a Microsoft Stroke, this will split the stroke into indices.Length + 1 strokes. /// </summary> /// <param name="toSplit">Stroke to split</param> /// <param name="indices">Indices to split at</param> private Microsoft.Ink.Stroke[] splitMStroke(Microsoft.Ink.Stroke toSplit, float[] indices) { //Sort the indices to split Array.Sort(indices); //Reverse them Array.Reverse(indices); //We will walk along, and break up one stroke each time Microsoft.Ink.Stroke secondStroke; //Here is our array that we will add to the hashtable later Microsoft.Ink.Stroke[] strokes = new Microsoft.Ink.Stroke[indices.Length + 1]; //Here is what will happen... imagine this in the stroke: // // 5 4 3 2 1 // ========================================================================================== // 0 25.2 50.7 82.3 90.1 111.2 stroke.Count // //It will make the cuts in reverse order according to the indices, highest indices first //Then it adds each stroke to the array, following into the hashtable int current = 0; foreach (float index in indices) { //Split up the stroke secondStroke = toSplit.Split(index); //Add the latter one strokes[current++] = secondStroke; } //Dont forget the very first stroke strokes[current] = toSplit; int id = toSplit.Id; //Now add it to idToSubstrokes if (this.idToMSubstrokes.ContainsKey(id)) { this.idToMSubstrokes[id] = strokes; } else { this.idToMSubstrokes.Add(id, strokes); //idToMicroSubstrokes.Add(id, strokes); } return(strokes); }
/// <summary> /// Given a Stroke and a GUID, checks the Stroke's PacketDescription to see if the field corresponding to the GUID is there. /// </summary> /// <param name="stroke">Stroke to have it's PacketDescription checked</param> /// <param name="pp">GUID of the field that are checking to see if the PacketDescription contains.</param> /// <returns>bool that is true if the Stroke's PacketDescription has a field corresponding with the GUID.</returns> private bool IsPropertyIncluded(Microsoft.Ink.Stroke stroke, Guid pp) { foreach (Guid g in stroke.PacketDescription) { if (g == pp) { return(true); } } return(false); }
private void CreateStrokes() { if (theInk.Strokes.Count > 0) { return; } points = new Point[] { new Point(0, 0), new Point(100, 100) }; points2 = new Point[] { new Point(0, 0), new Point(150, 150) }; stroke1 = theInk.CreateStroke(points); stroke2 = theInk.CreateStroke(points); }
public FormInput(string caption, string label, string txt, bool ML, gInk.Root rt = null, Microsoft.Ink.Stroke stk = null) { InitializeComponent(); // local this.btOK.Text = rt.Local.ButtonOkText; this.btCancel.Text = rt.Local.ButtonCancelText; this.FontBtn.Text = rt.Local.ButtonFontText; boxingCb.Items.AddRange(rt.Local.TextFramingText.Split(';')); Text = caption; captionLbl.Text = label; if (ML) { InputML.Visible = true; InputML.Text = txt; ActiveControl = InputML; } else { InputSL.Visible = true; InputSL.Text = txt; ActiveControl = InputSL; } Root = rt; stroke = stk; if (stroke == null) { FontBtn.Visible = false; boxingCb.Visible = false; } else { FontBtn.Visible = true; ColorBtn.Visible = true; boxingCb.Visible = true;// !stk.ExtendedProperties.Contains(Root.ISTAG_GUID); FontDlg.Font = new Font((string)stk.ExtendedProperties[Root.TEXTFONT_GUID].Data, (float)stk.ExtendedProperties[Root.TEXTFONTSIZE_GUID].Data, (System.Drawing.FontStyle)stk.ExtendedProperties[Root.TEXTFONTSTYLE_GUID].Data); InputML.TextChanged += new System.EventHandler(this.InputML_TextChanged); int i = (stk.ExtendedProperties.Contains(Root.ISSTROKE_GUID) ? 1 : 0) + (stk.ExtendedProperties.Contains(Root.ISFILLEDWHITE_GUID) ? 2 : 0) + (stk.ExtendedProperties.Contains(Root.ISFILLEDBLACK_GUID) ? 4 : 0); boxingCb.Text = boxingCb.Items[i].ToString(); Saved_Txt = InputML.Text; Saved_Da = stk.DrawingAttributes.Clone(); Saved_Font = (Font)FontDlg.Font.Clone(); Saved_Frame = stk.ExtendedProperties.Contains(Root.ISSTROKE_GUID); Saved_White = stk.ExtendedProperties.Contains(Root.ISFILLEDWHITE_GUID); Saved_Black = stk.ExtendedProperties.Contains(Root.ISFILLEDBLACK_GUID); } }
/// <summary> /// Constructor. /// </summary> /// <param name="oInk"></param> /// <param name="splitStroke"></param> /// <param name="pointInter"></param> /// <param name="mIdToIndices"></param> /// <param name="progressBar"></param> public SplitStrokeAt(Microsoft.Ink.InkOverlay oInk, Microsoft.Ink.Stroke splitStroke, System.Drawing.Point[] pointInter, Dictionary <int, List <float> > mIdToIndices, System.Windows.Forms.ProgressBar progressBar) { this.oInk = oInk; this.splitStroke = splitStroke; this.pointInter = pointInter; this.mIdToIndices = mIdToIndices; this.progressBar = progressBar; this.newMIdToIndices = new Dictionary <int, List <float> >(); }
/// <summary> /// Constructor. /// </summary> /// <param name="oInk"></param> /// <param name="splitStroke"></param> /// <param name="pointInter"></param> /// <param name="mIdToIndices"></param> /// <param name="progressBar"></param> public SplitStrokeAt(Microsoft.Ink.InkOverlay oInk, Microsoft.Ink.Stroke splitStroke, System.Drawing.Point[] pointInter, Hashtable mIdToIndices, System.Windows.Forms.ProgressBar progressBar) { this.oInk = oInk; this.splitStroke = splitStroke; this.pointInter = pointInter; this.mIdToIndices = mIdToIndices; this.progressBar = progressBar; this.newMIdToIndices = new Hashtable(); }
/// <summary> /// Get the Point at a floating point index. /// See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/tpcsdk10/lonestar/Microsoft.Ink/Classes/stroke/Methods/getpoint.asp. /// </summary> /// <param name="theStroke">Stroke</param> /// <param name="theFIndex">Floating point index</param> /// <returns>A point on the stroke</returns> private System.Drawing.Point LocatePoint(Microsoft.Ink.Stroke theStroke, float theFIndex) { System.Drawing.Point ptResult = theStroke.GetPoint((int)theFIndex); float theFraction = theFIndex - (int)theFIndex; if (theFraction > 0.0f) { System.Drawing.Point ptDelta = theStroke.GetPoint((int)theFIndex + 1); ptResult.X += (int)((ptDelta.X - ptResult.X) * theFraction); ptResult.Y += (int)((ptDelta.Y - ptResult.Y) * theFraction); } return(ptResult); }
/// <summary> /// <see cref="InvalidateStroke"/> /// </summary> /// <param name="iStroke">The Ink stroke to invalidate</param> /// <param name="padding">Number of pixels to pad invalidation /// rectangle in Ink space pixels</param> public void InvalidateStroke(Microsoft.Ink.Stroke iStroke, int padding) { using (Graphics g = InkPicture.CreateGraphics()) { Rectangle bb = iStroke.GetBoundingBox(); System.Drawing.Point upperLeft = new System.Drawing.Point(bb.X - padding, bb.Y - padding); System.Drawing.Point lowerRight = new System.Drawing.Point(bb.Right + padding, bb.Bottom + padding); InkPicture.Renderer.InkSpaceToPixel(g, ref upperLeft); InkPicture.Renderer.InkSpaceToPixel(g, ref lowerRight); InkPicture.Invalidate(new Rectangle(upperLeft.X, upperLeft.Y, lowerRight.X, lowerRight.Y)); } }
private void calculateGuidToMStroke() { this.guidToMStroke = new Hashtable(); IDictionaryEnumerator enumerator = this.idToCStroke.GetEnumerator(); while (enumerator.MoveNext()) { int id = (int)enumerator.Key; Microsoft.Ink.Stroke mStroke = this.getMStrokeById(id); string guid = ((Stroke)enumerator.Value).Id; this.guidToMStroke.Add(guid, mStroke); } }
/// <summary> /// Returns the bounding box for the given shape in ink space coordinates. Optionall colors the strokes /// the default color for non-wire symbols. /// <see cref="UIConstants.TextFeedbackMechanismSymbolColor"/> /// </summary> /// <param name="shape">the shape for which the bounding box will be calculated</param> /// <param name="substroke2InkTable">A hashtable mapping Ink Stroke IDs to Sketch Substroke IDs. /// This hashtable allows the Feedback Mechanism to assocate Ink Strokes drawn to screen /// with their corresponding (labeled) Sketch substrokes.</param> /// <param name="colorStrokes">True iff the microsoft ink strokes should be colored while calculating /// the bounding box (for efficiency's sake).</param> /// <returns>A System.Drawing.Rectangle representing the bounding box /// for the given shape (in ink space coordinates)</returns> private Rectangle calculateBoundingBox(Sketch.Shape shape, Hashtable substroke2InkTable, bool colorStrokes) { // Compute the bounding box of all the ink strokes // associated with this shape Rectangle boundingBox = Rectangle.Empty; foreach (Sketch.Substroke substroke in shape.Substrokes) { if (!substroke2InkTable.Contains(substroke.XmlAttrs.Id)) { // If, for some reason, there is no ink stroke // that corresponds to this substroke, skip it continue; } Microsoft.Ink.Stroke iStroke = (Microsoft.Ink.Stroke)substroke2InkTable[substroke.XmlAttrs.Id]; if (colorStrokes) { iStroke.DrawingAttributes.Color = UIConstants.TextFeedbackMechanismSymbolColor; } Rectangle strokeBox = iStroke.GetBoundingBox(); if (boundingBox.IsEmpty) { boundingBox = strokeBox; } else { if (strokeBox.X < boundingBox.X) { boundingBox.X = strokeBox.X; } if (strokeBox.Y < boundingBox.Y) { boundingBox.Y = strokeBox.Y; } if (strokeBox.Bottom > boundingBox.Bottom) { boundingBox.Height = strokeBox.Bottom - boundingBox.Y; } if (strokeBox.Right > boundingBox.Right) { boundingBox.Width = strokeBox.Right - boundingBox.X; } } } return(boundingBox); }
/// <summary> /// HACK need this constructor to get this class to compile. /// This Constructor simply creates a new LabelerPanel. Do not use it. /// <see cref="http://blogs.msdn.com/jmanning/archive/2005/09/21/472456.aspx"/> /// </summary> /*public LabelerPanelAdatper(CommandManager CM, DomainInfo domainInfo) * : base(CM, domainInfo) * { * }*/ /// <summary> /// Constructor. Wraps the given SketchPanel /// </summary> /// <param name="panel">The panel to wrap</param> public LabelerPanelAdatper(SketchPanel panel) { sketchPanel = panel; // Build Ink 2 Sketch map base.mIdToSubstroke = new Dictionary <int, Substroke>(); foreach (Substroke sub in sketchPanel.InkSketch.Sketch.Substrokes) { Microsoft.Ink.Stroke iStroke = sketchPanel.InkSketch.GetInkStrokeBySubstrokeId(sub.XmlAttrs.Id); base.mIdToSubstroke.Add(iStroke.Id, sub); } base.sketch = sketchPanel.InkSketch.Sketch; base.sketchInk = sketchPanel.InkPicture as Labeler.mInkPicture; }
private void DisplayFragmentPoints(Sketch.Stroke stroke, int index) { Sketch.Point[] points = stroke.Points; System.Drawing.Point coordinates = new System.Drawing.Point((int)points[index].X, (int)points[index].Y); // Set the fragment point with drawing attributes Microsoft.Ink.Stroke fragPt = overlayInk.Ink.CreateStroke(new System.Drawing.Point[1] { coordinates }); fragPt.DrawingAttributes = this.fragmentPtAttributes; this.fragmentPtsDrawn.Add(coordinates); }
private void DisplayFragmentPoints(Sketch.Stroke stroke, List <int> indices) { Sketch.Point[] points = stroke.Points; foreach (int index in indices) { System.Drawing.Point pt = new System.Drawing.Point((int)points[index].X, (int)points[index].Y); // Set the fragment point with drawing attributes Microsoft.Ink.Stroke fragPt = this.overlayInk.Ink.CreateStroke(new System.Drawing.Point[1] { pt }); fragPt.DrawingAttributes = this.fragmentPtAttributes; } }
/// <summary> /// Receive Presenter2 stroke /// </summary> /// <param name="drawStroke"></param> public void ReceiveStroke(ArchiveRTNav.RTDrawStroke drawStroke) { int slideIndex; slideIndex = slideMap.GetMapping(drawStroke.SlideIndex, drawStroke.DeckGuid); InkScribble s = (InkScribble)this.SlideDeck.GetOverlay(slideIndex).Scribble; Ink.Stroke foundStroke; bool found = FastFindStrokeFromGuid(s, drawStroke.Guid, out foundStroke, NEW_GUID_TAG); if (found) { s.Ink.DeleteStroke(foundStroke); } Ink.Ink ink = drawStroke.Ink; lock (this) { Rectangle r = ink.Strokes.GetBoundingBox(); r.X = (int)(r.X * XinkScaleFactor); r.Y = (int)(r.Y * YinkScaleFactor); r.Width = (int)(r.Width * XinkScaleFactor); r.Height = (int)(r.Height * YinkScaleFactor); s.Ink.AddStrokesAtRectangle(ink.Strokes, r); // Make note of the ink's strokes in the guidtable. // ASSUME that these strokes went on the end. int sCount = s.Ink.Strokes.Count; int newCount = ink.Strokes.Count; for (int i = sCount - newCount; i < sCount; i++) { Ink.Stroke stroke = s.Ink.Strokes[i]; if (stroke.ExtendedProperties.Contains(NEW_GUID_TAG)) { Guid guid = Guid.Empty; try { //Saw this except once. Couldn't repro. Suspect corrupted data. guid = new Guid((string)stroke.ExtendedProperties[NEW_GUID_TAG].Data); } catch { continue; } this.myGuidTable[new ScribbleIntPair(s, stroke.Id)] = guid; this.myGuidReverseTable[guid] = new ScribbleIntPair(s, stroke.Id); } } } }
/// <summary> /// Displays a tooltip based on the label of the nearest stroke. /// </summary> /// <param name="sender">event sender</param> /// <param name="e">event information, includign mouse location</param> private void sketchPicture_MouseMove(object sender, MouseEventArgs e) { /// /// HACK: turn off tooptip /// return; // Get the current mouse position and convert it into InkSpace System.Drawing.Point mousePt = new System.Drawing.Point(e.X, e.Y); Graphics graphics = sketchPicture.CreateGraphics(); sketchPicture.Renderer.PixelToInkSpace(graphics, ref mousePt); // Get the Microsoft Stroke closest to the mouse pointer float strokePt, distance; Microsoft.Ink.Stroke closestMSubstroke = sketchPicture.Ink.NearestPoint(mousePt, out strokePt, out distance); if (closestMSubstroke == null) { return; } // Fire tooltip if the mouse pointer is close enough if (distance < UIConstants.ColorFeedbackMechanismTooltipDistanceThreshold) { // Get the stroke's label, if it has one if (!ink2sketchLabelTable.Contains(closestMSubstroke.Id)) { return; } string label = (string)ink2sketchLabelTable[closestMSubstroke.Id]; // Show the ToolTip this.toolTip.SetToolTip(sketchPicture, label); this.toolTip.Active = true; } else { // Don't show the ToolTip if the mouse pointer is not close this.toolTip.Active = false; } }
public FormInput(string caption, string label, string txt, bool ML, gInk.Root rt = null, Microsoft.Ink.Stroke stk = null) { InitializeComponent(); // local this.btOK.Text = rt.Local.ButtonOkText; this.btCancel.Text = rt.Local.ButtonCancelText; this.FontBtn.Text = rt.Local.ButtonFontText; Text = caption; captionLbl.Text = label; if (ML) { InputML.Visible = true; InputML.Text = txt; ActiveControl = InputML; } else { InputSL.Visible = true; InputSL.Text = txt; ActiveControl = InputSL; } Root = rt; stroke = stk; if (stroke == null) { FontBtn.Visible = false; } else { FontBtn.Visible = true; ColorBtn.Visible = true; FontDlg.Font = new Font((string)stk.ExtendedProperties[Root.TEXTFONT_GUID].Data, (float)stk.ExtendedProperties[Root.TEXTFONTSIZE_GUID].Data, (System.Drawing.FontStyle)stk.ExtendedProperties[Root.TEXTFONTSTYLE_GUID].Data); InputML.TextChanged += new System.EventHandler(this.InputML_TextChanged); } }
public strokeInfoForm(Featurefy.FeatureStroke strokeFeatures, Featurefy.FeatureSketch sketchFeatures, Microsoft.Ink.Stroke inkStroke, Substroke ss) { InitializeComponent(); this.inkMovedX = 0.0f; this.inkMovedY = 0.0f; this.scale = 2.0f; pictureInk = new InkPicture(); pictureInk.Bounds = new Rectangle(0, 0, this.Width - dataView.Width, this.Height); Controls.Add(pictureInk); r = new Renderer(); g = this.pictureInk.CreateGraphics(); pictureInk.Painted += new InkOverlayPaintedEventHandler(pictureInk_Painted); _sketchFeatures = sketchFeatures; _strokeFeatures = strokeFeatures; _inkStroke = inkStroke; _substroke = ss; this.pictureInk.Ink.CreateStroke(_inkStroke.GetPoints()); this.pictureInk.Ink.Strokes[0].DrawingAttributes.Color = Color.Red; populateListView(); //drawPrimitives(this.features); }
private bool FindStrokeFromGuid(InkScribble scribble, Guid guid, out Ink.Stroke stroke, Guid guidTag) { Ink.Ink ink = scribble.Ink; // Check if the guid tables are out of date. This might be indicated by either: // * The guid is not in the reverse table. // * The reverse table entry's scribble does not match the given scribble. // If the tables are out of date, update the entries for this scribble object. if (!this.myGuidReverseTable.Contains(guid) || ((ScribbleIntPair)this.myGuidReverseTable[guid]).scribble != scribble) { // Ensure that, at the least, the stale entry is removed. this.myGuidReverseTable.Remove(guid); // Refresh entries for all strokes in this scribble. foreach (Ink.Stroke s in ink.Strokes) { try { if (s.ExtendedProperties.DoesPropertyExist(guidTag)) { Guid strokeGuid = new Guid((string)s.ExtendedProperties[guidTag].Data); this.myGuidReverseTable[strokeGuid] = new ScribbleIntPair(scribble, s.Id); this.myGuidTable[new ScribbleIntPair(scribble, s.Id)] = strokeGuid; } } catch { //this try/catch because I once saw an exception thrown here. Not sure if it was a bug // in the data, the TPC SDK, or in my code.. Anyway it seemed safe to ignore. } } } // If the guid is still not in the table, it is not found. if (!this.myGuidReverseTable.Contains(guid)) { stroke = null; return(false); } // Can we find the specific id sought? ScribbleIntPair pair = (ScribbleIntPair)this.myGuidReverseTable[guid]; //This try/catch is a hack to deal with multiple-play (archive) scenario. //I believe the real fix is to catch WMP stop and postion change events and //to rebuild guid tables and InkScribble appropriately for the new media position. Ink.Strokes targetStrokes = null; try { targetStrokes = ink.CreateStrokes(new int[] { pair.id }); } catch { stroke = null; return(false); } if (targetStrokes.Count < 1) { stroke = null; return(false); } // Found it. stroke = targetStrokes[0]; return(true); }
/// <summary> /// Set Ink stroke text labels based upon domain /// </summary> public override void FireFeedbackMechanism(Sketch.Sketch sketch, InkPicture inkPicture, Hashtable ink2sketchIdTable, FeedbackContext context) { // // Preprocessing // // Remove all current textboxes from the inkPicture // and clear the table of textboxes; start out fresh foreach (Label currentLabel in textboxList) { inkPicture.Controls.Remove(currentLabel); } textboxList.Clear(); // Build hashtable of sketch substroke Ids to ink strokes Hashtable substroke2InkTable = new Hashtable(); System.Guid currentGuid; foreach (Microsoft.Ink.Stroke iStroke in inkPicture.Ink.Strokes) { // If this ink stroke does not have a // corresponding sketch stroke, skip it if (!ink2sketchIdTable.Contains(iStroke.Id)) { continue; } currentGuid = (System.Guid)ink2sketchIdTable[iStroke.Id]; substroke2InkTable.Add(currentGuid, iStroke); } // // Iterate through shapes // Graphics g = inkPicture.CreateGraphics(); foreach (Sketch.Shape shape in sketch.Shapes) { // Get label of this shape string label = shape.Substrokes[0].GetFirstLabel(); // // Color wires and don't label them // if (label == "Wire") { foreach (Sketch.Substroke substroke in shape.Substrokes) { if (!substroke2InkTable.Contains(substroke.XmlAttrs.Id)) { // If, for some reason, there is no ink stroke // that corresponds to this substroke, skip it continue; } Microsoft.Ink.Stroke iStroke = (Microsoft.Ink.Stroke)substroke2InkTable[substroke.XmlAttrs.Id]; iStroke.DrawingAttributes.Color = UIConstants.TextFeedbackMechanismWireColor; } } // // Draw boxes over input/output labels // else if (label == "Label") { // For efficiency's sake, we color the strokes while calculating the bounding box. Rectangle boundingBox = calculateBoundingBox(shape, substroke2InkTable, true); // Devise the (x,y) location of the text label on the screen System.Drawing.Point upperLeft = new System.Drawing.Point(boundingBox.X, boundingBox.Y); System.Drawing.Point lowerRight = new System.Drawing.Point(boundingBox.Right, boundingBox.Bottom); inkPicture.Renderer.InkSpaceToPixel(g, ref upperLeft); inkPicture.Renderer.InkSpaceToPixel(g, ref lowerRight); upperLeft.X -= 10; upperLeft.Y -= 10; lowerRight.X += 10; lowerRight.Y += 10; int bwidth = lowerRight.X - upperLeft.X; int bheight = lowerRight.Y - upperLeft.Y; // Create bounding box for label // HACK!! TODO: draw a transparent label // instead of four labels to make // a box around the symbol Label topLabel = new Label(); Label bottomLabel = new Label(); Label leftLabel = new Label(); Label rightLabel = new Label(); topLabel.UseMnemonic = false; bottomLabel.UseMnemonic = false; leftLabel.UseMnemonic = false; rightLabel.UseMnemonic = false; topLabel.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; bottomLabel.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; leftLabel.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; rightLabel.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; // Set label positions topLabel.Location = upperLeft; topLabel.Height = 1; topLabel.Width = bwidth; bottomLabel.Location = new System.Drawing.Point(upperLeft.X, upperLeft.Y + bheight); bottomLabel.Height = 1; bottomLabel.Width = bwidth; leftLabel.Location = new System.Drawing.Point(upperLeft.X, upperLeft.Y); leftLabel.Height = bheight; leftLabel.Width = 1; rightLabel.Location = new System.Drawing.Point(upperLeft.X + bwidth, upperLeft.Y); rightLabel.Height = bheight; rightLabel.Width = 1; topLabel.Enabled = true; bottomLabel.Enabled = true; leftLabel.Enabled = true; rightLabel.Enabled = true; inkPicture.Controls.Add(topLabel); inkPicture.Controls.Add(bottomLabel); inkPicture.Controls.Add(leftLabel); inkPicture.Controls.Add(rightLabel); textboxList.Add(topLabel); textboxList.Add(bottomLabel); textboxList.Add(leftLabel); textboxList.Add(rightLabel); } // // Draw labels for other symbols // else { // For efficiency's sake, we color the strokes while calculating the bounding box. Rectangle boundingBox = calculateBoundingBox(shape, substroke2InkTable, true); // Devise the (x,y) location of the text label on the screen System.Drawing.Point center = new System.Drawing.Point(boundingBox.Width / 2 + boundingBox.Left, boundingBox.Height / 2 + boundingBox.Top); System.Drawing.Point upperLeft = new System.Drawing.Point(boundingBox.X, boundingBox.Y); System.Drawing.Point lowerRight = new System.Drawing.Point(boundingBox.Right, boundingBox.Bottom); inkPicture.Renderer.InkSpaceToPixel(g, ref center); inkPicture.Renderer.InkSpaceToPixel(g, ref upperLeft); inkPicture.Renderer.InkSpaceToPixel(g, ref lowerRight); center.X += inkPicture.Bounds.X; center.Y += inkPicture.Bounds.Y; // Create textbox for label Label textLabel = new Label(); textLabel.UseMnemonic = false; textLabel.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; textLabel.Text = label; textLabel.TextAlign = ContentAlignment.MiddleCenter; textLabel.AutoSize = true; // Position label so that it is either on top of the symbol, // or, if the symbol is very small, along side the symbol int bwidth = lowerRight.X - upperLeft.X; int bheight = lowerRight.Y - upperLeft.Y; if (textLabel.Width < bwidth && textLabel.Height < bheight) { center.X -= textLabel.Width / 2; center.Y -= textLabel.Height / 2; } else { // If taller than is wide, place label to the right; // else place label just above symbol if (boundingBox.Height > boundingBox.Width) { center.Y -= textLabel.Height / 2; center.X += bwidth / 2; } else { center.Y += bheight / 2; center.X -= textLabel.Width / 2; } } textLabel.Location = center; textLabel.Enabled = true; inkPicture.Controls.Add(textLabel); textboxList.Add(textLabel); } } }
/// <summary> /// Converts a single Microsoft Ink stroke to a Sketch stroke. /// </summary> /// <param name="inkStroke">The Microsoft Ink stroke to convert</param> /// <returns>A Sketch stroke.</returns> /// <seealso cref="ReadJnt.StripStrokeData">This function wraps StripStrokeData()</seealso> public Sketch.Stroke InkStroke2SketchStroke(Microsoft.Ink.Stroke inkStroke) { return(InkStroke2SketchStroke(inkStroke, null, false)); }
/// <summary> /// Takes an Ink.Stroke and outputs an internal representation that can /// then be output to an XML file /// </summary> /// <param name="inkStroke">Ink.Stroke which will have extracted from it the information necessary to store a Stroke in MIT XML.</param> /// <param name="transf">Transformation matrix to shift the stroke by</param> /// <param name="shift">Boolean for if we should shift by the transformation matrix</param> /// <returns>PointsAndShape object that stores the extracted information.</returns> public static Sketch.Stroke StripStrokeData(Microsoft.Ink.Stroke inkStroke, Matrix transf, bool shift) { int i; int length; // Get the timestamp for the function using an undocumented GUID (Microsoft.Ink.StrokeProperty.TimeID) to // get the time as a byte array, which we then convert to a long ulong theTime; if (inkStroke.ExtendedProperties.Contains(Microsoft.Ink.StrokeProperty.TimeID) && (inkStroke.ExtendedProperties[Microsoft.Ink.StrokeProperty.TimeID] != null)) { byte[] timeBits = inkStroke.ExtendedProperties[Microsoft.Ink.StrokeProperty.TimeID].Data as byte[]; // Filetime format ulong fileTime = BitConverter.ToUInt64(timeBits, 0); // MIT time format theTime = (fileTime - 116444736000000000) / 10000; //string time = theTime.ToString(); } else { //theTime = (ulong)System.DateTime.Now.Ticks; //theTime = ((ulong)System.DateTime.Now.Ticks - 116444736000000000) / 10000; theTime = ((ulong)DateTime.Now.ToFileTime() - 116444736000000000) / 10000; } // Grab X and Y int[] xData = inkStroke.GetPacketValuesByProperty(Microsoft.Ink.PacketProperty.X); int[] yData = inkStroke.GetPacketValuesByProperty(Microsoft.Ink.PacketProperty.Y); if (shift) { // Shift X and Y according to transformation matrix System.Drawing.Point[] pointData = new System.Drawing.Point[xData.Length]; length = xData.Length; for (i = 0; i < length; i++) { pointData[i] = new System.Drawing.Point(xData[i], yData[i]); } transf.TransformPoints(pointData); //Console.WriteLine("x: " + (pointData[0].X - xData[0]) + " y: " + (pointData[0].Y - yData[0])); for (i = 0; i < length; i++) { xData[i] = pointData[i].X; yData[i] = pointData[i].Y; } } Microsoft.Ink.DrawingAttributes drawingAttributes = inkStroke.DrawingAttributes; System.Drawing.Rectangle boundingBox = inkStroke.GetBoundingBox(); // Grab the color int color = drawingAttributes.Color.ToArgb(); // THIS IS DRAWING POINT (PENTIP) HEIGHT AND WIDTH... WE DONT HAVE ANYWHERE TO PUT IT... //string height = inkStroke.DrawingAttributes.Height.ToString(); //string width = inkStroke.DrawingAttributes.Width.ToString(); float penWidth = drawingAttributes.Width; float penHeight = drawingAttributes.Height; // Grab height and width of total stroke //float height = boundingBox.Height; //float width = boundingBox.Width; // Grab penTip string penTip = drawingAttributes.PenTip.ToString(); // Grab raster string raster = drawingAttributes.RasterOperation.ToString(); //float x = Convert.ToSingle(boundingBox.X); //float y = Convert.ToSingle(boundingBox.Y); //float leftx = Convert.ToSingle(boundingBox.Left); //float topy = Convert.ToSingle(boundingBox.Top); // If the pressure data is included take it, otherwise set to 255/2's // Not all pressure data is in the range of 0 - 255. Some tablets // register pressure in the range 0 - 1023, while others are 0 - 32768 int[] pressureData; if (ReadJnt.IsPropertyIncluded(inkStroke, Microsoft.Ink.PacketProperty.NormalPressure)) { pressureData = inkStroke.GetPacketValuesByProperty(Microsoft.Ink.PacketProperty.NormalPressure); int max = 0; foreach (int p in pressureData) { max = Math.Max(max, p); } if (max > 1024) // Tablet reading in range 0 - 32767 { double conversion = 255.0 / 32767.0; List <int> temp = new List <int>(pressureData.Length); foreach (int p in pressureData) { temp.Add((int)(p * conversion)); } pressureData = temp.ToArray(); } else if (max > 255) // Tablet reading in range 0 - 1023 { double conversion = 255.0 / 1023.0; List <int> temp = new List <int>(pressureData.Length); foreach (int p in pressureData) { temp.Add((int)(p * conversion)); } pressureData = temp.ToArray(); } } else { pressureData = new int[xData.Length]; length = pressureData.Length; for (i = 0; i < length; ++i) { pressureData[i] = (255 - 0) / 2; } } // If the time data is included take it, otherwise set to the timestamp plus and increment ulong[] adjustedTime = new ulong[xData.Length]; int[] timerTick; if (ReadJnt.IsPropertyIncluded(inkStroke, Microsoft.Ink.PacketProperty.TimerTick)) { timerTick = inkStroke.GetPacketValuesByProperty(Microsoft.Ink.PacketProperty.TimerTick); length = timerTick.Length; for (i = 0; i < length; i++) { // This may be incorrect, we never encountered this because Microsoft Journal doesn't save TimerTick data. // We know that the timestamp of a stroke is made when the pen is lifted. // Add the time of the stroke to each offset adjustedTime[i] = theTime + (ulong)timerTick[i] * 10000; } } else { timerTick = new int[xData.Length]; length = timerTick.Length; for (i = 0; i < length; i++) { // We believe this to be the standard sample rate. The multiplication by 1,000 is to convert from // seconds to milliseconds. // // Our time is in the form of milliseconds since Jan 1, 1970 // // NOTE: The timestamp for the stroke is made WHEN THE PEN IS LIFTED adjustedTime[i] = theTime - (ulong)((1 / SAMPLE_RATE * 1000) * (length - i)); } } // Create the array of ID's as new Guid's Guid[] idData = new Guid[xData.Length]; length = idData.Length; for (i = 0; i < length; i++) { idData[i] = Guid.NewGuid(); } // Create the internal representation Sketch.Stroke converterStroke = new Sketch.Stroke(); converterStroke.Name = "stroke"; converterStroke.Time = (ulong)theTime; converterStroke.Source = "Converter"; // Add all of the points to the stroke length = inkStroke.PacketCount; List <Point> pointsToAdd = new List <Point>(); for (i = 0; i < length; i++) { float currX = Convert.ToSingle(xData[i]); float currY = Convert.ToSingle(yData[i]); XmlStructs.XmlPointAttrs attrs = new XmlStructs.XmlPointAttrs( currX, currY, Convert.ToUInt16(pressureData[i]), Convert.ToUInt64(adjustedTime[i]), "point", idData[i]); Sketch.Point toAdd = new Sketch.Point(attrs); } //NOTE: X, Y, WIDTH, HEIGHT done later... boundingbox seems to be off Sketch.Substroke substroke = new Sketch.Substroke(pointsToAdd); substroke.Name = "substroke"; substroke.Color = color; substroke.PenTip = penTip; substroke.PenWidth = penWidth; substroke.PenHeight = penHeight; substroke.Raster = raster; substroke.Source = "ConverterJnt"; substroke.Start = idData[0]; substroke.End = idData[idData.Length - 1]; converterStroke.AddSubstroke(substroke); return(converterStroke); }
/// <summary> /// Converts a single Microsoft Ink stroke to a Sketch stroke. Supports using a /// transformation matrix /// </summary> /// <param name="inkStroke">The Microsoft Ink stroke to convert</param> /// <param name="transf">Transformation matrix for stroke shifting</param> /// <param name="shift">True iff the transformation shift matrix should be used</param> /// <returns>A Sketch stroke.</returns> /// <seealso cref="ReadJnt.StripStrokeData">This function wraps StripStrokeData()</seealso> public Sketch.Stroke InkStroke2SketchStroke(Microsoft.Ink.Stroke inkStroke, Matrix transf, bool shift) { return(StripStrokeData(inkStroke, transf, shift)); }
/// <summary> /// Break up the Microsoft stroke, and associated Converter stroke, at the given indices and add it to the document /// </summary> /// <param name="mStroke">The Microsoft Stroke</param> /// <param name="indices">The indices to split at</param> /// <param name="document">The document to add to</param> public void splitStrokes(Microsoft.Ink.Stroke mStroke, float[] indices, MakeXML document) { this.splitStrokes(mStroke.Id, indices, document); }
/// <summary> /// Invalidates the bounding box enclosing the given stroke, causing this area /// of the screen to repaint. Useful for causing a (only) small portion of the InkPicture /// to repaint, thus minimizing screen flicker. /// </summary> /// <param name="iStroke">The Ink stroke to invalidate</param> public void InvalidateStroke(Microsoft.Ink.Stroke iStroke) { InvalidateStroke(iStroke, 0); }
/// <summary> /// Creates the strokes in this xml document as C# strokes and adds them to the corresponding Ink object. /// We cannot create new strokes with the same Id's that we have in the MIT XML format, so instead we /// return a hash table mapping the created strokes' Ids (1, 2, ... , n) with the strokes. /// </summary> /// /// <returns>A Hashtable that holds links back to the Converter strokes</returns> public Hashtable getIdToCStroke(Sketch sketch, Microsoft.Ink.Ink inkObject) { ArrayList strokes = sketch.Shapes; ArrayList points = sketch.Points; Hashtable retTable = new Hashtable(); // Create a hashtable between points and IDs for easy access Hashtable pointTable = sketch.IdToPoint; // Now create the C# strokes foreach (Shape s in strokes) { Stroke st = new Stroke(s); // first check to be sure it's a matching shape if (st.matches(Stroke.ShapeType.STROKE)) { // Get all of the stroke's points ArrayList pts = s.getArgIds(); System.Drawing.Point[] xypts = new System.Drawing.Point[pts.Count]; //int[] pressureData = new int[pts.Count]; //int[] timerData = new int[pts.Count]; int index = 0; //Console.WriteLine( "loading stroke..."); foreach (string id in pts) { Point p = (Point)pointTable[id]; st.Points.Add(p); st.Args.Add(new Stroke.Arg("Point", p.Id)); // Just get the x and the y, ignore the rest int x = Convert.ToInt32(p.X); int y = Convert.ToInt32(p.Y); //Console.WriteLine( "[x: {0}, y: {1}]", x, y ); xypts[index] = new System.Drawing.Point(x, y); //pressureData[index] = (int)p.Pressure; //timerData[index] = (int)p.Time; ++index; } Microsoft.Ink.Stroke newStroke = inkObject.CreateStroke(xypts); /* * // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dntablet/html/TimeStampsBestPractices.asp * // mike used: 8fe68ce5-c39c-4f52-afbb-65344e8e49ff * newstroke.ExtendedProperties.Add(new Guid("8A54CF58-97E6-4fc5-8F06-F8BAD2E19B22"), (long)s.Time); * * // newstroke.SetPacketValuesByProperty(Microsoft.Ink.PacketProperty.NormalPressure, pressureData); * newstroke.SetPacketValuesByProperty(Microsoft.Ink.PacketProperty.TimerTick, timerData); */ retTable.Add(newStroke.Id, st); } } return(retTable); }