public LinkedPoint(double X, double Y, Sketch.Substroke par) { this.x = X; this.y = Y; this.parent = par; index = null; }
/// <summary> /// Constructor. Create from Shape. Shallow copy of subshapes, deep copy of substrokes. /// </summary> /// <param name="shape">A Shape.</param> public Shape(Shape shape) { this.Name = shape.Name; List <Substroke> newSubstrokes = new List <Substroke>(shape._substrokes.Count); foreach (Substroke s in shape._substrokes) { Substroke newS = s.CloneConstruct(); newS.ParentShape = this; newSubstrokes.Add(newS); } _substrokes = new List <Substroke>(shape._substrokes.Count); foreach (Substroke s in newSubstrokes) { AddSubstroke(s); } _xmlAttributes = shape._xmlAttributes.Clone(); AlreadyGrouped = shape.AlreadyGrouped; AlreadyLabeled = shape.AlreadyLabeled; UserLabeled = shape.UserLabeled; TemplateName = shape.TemplateName; TemplateDrawing = shape.TemplateDrawing; }
/// <summary> /// Add a Substroke to this shape /// </summary> /// <param name="substroke">A Substroke</param> public void AddSubstroke(Substroke substroke) { if (!this.substrokes.Contains(substroke)) { int low = 0; int high = this.substrokes.Count - 1; int mid; while (low <= high) { mid = (high - low) / 2 + low; if ((ulong)substroke.XmlAttrs.Time < (ulong)((Substroke)this.substrokes[mid]).XmlAttrs.Time) { high = mid - 1; } else { low = mid + 1; } } this.substrokes.Insert(low, substroke); if (substroke.ParentShapes != null && !substroke.ParentShapes.Contains(this)) { substroke.ParentShapes.Add(this); } UpdateSpatialAttributes(this); } }
/// <summary> /// Constructor for Single Stroke Features. Calculates Single Stroke Features /// </summary> /// <param name="substroke">Stroke to find feature values for</param> /// <param name="featureList">Which features to use</param> public FeatureStroke(Sketch.Substroke substroke, Dictionary <string, bool> featureList) : this(substroke) { featuresToUse = featureList; CalculateSingleStrokeFeatures(); }
/// <summary> /// Add the substroke into a new, labeled Shape. /// </summary> /// <param name="substroke">Substroke to be included in the label</param> /// <param name="label">Label's string</param> /// <param name="probability">Probability of a label's accuracy</param> /// <returns>The labeled shape added to the Sketch</returns> public Shape AddLabel(Substroke substroke, string label, double probability) { ArrayList tempArrayList = new ArrayList(); tempArrayList.Add(substroke); return(AddLabel(tempArrayList, label, probability)); }
/// <summary> /// Add the substroke into a new, labeled Shape. /// </summary> /// <param name="substroke">Substroke to be included in the label</param> /// <param name="label">Label's string</param> /// <returns>The labeled shape added to the Sketch</returns> public Shape AddLabel(Substroke substroke, string label) { ArrayList tempArrayList = new ArrayList(); tempArrayList.Add(substroke); return(AddLabel(tempArrayList, label)); }
/// <summary> /// Create a stroke from an InkStroke. Used when adding the stroke. /// </summary> /// <param name="stroke"></param> /// <param name="dtGuid"></param> /// <param name="SAMPLE_RATE"></param> public Stroke(System.Windows.Ink.Stroke stroke, Guid dtGuid, float SAMPLE_RATE) : this() { // Get the timestamp for the function using a const Guid ulong theTime; if (stroke.ContainsPropertyData(dtGuid)) { // MIT file format ulong fileTime = (ulong)stroke.GetPropertyData(dtGuid); theTime = (fileTime - 116444736000000000) / 10000; } else { theTime = ((ulong)DateTime.Now.ToFileTime() - 116444736000000000) / 10000; } // Set time data for each point and add it to the list of substroke's points List <Point> pointsToAdd = new List <Point>(); System.Windows.Input.StylusPointCollection stylusPoints = stroke.StylusPoints; int numPoints = stylusPoints.Count; for (int i = 0; i < numPoints; 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 System.Windows.Input.StylusPoint styPoint = stylusPoints[i]; ulong adjustedTime = theTime - (ulong)((1 / SAMPLE_RATE * 1000) * (numPoints - i)); Point toAdd = new Point((float)styPoint.X, (float)styPoint.Y, (float)styPoint.PressureFactor, Convert.ToUInt64(adjustedTime), "point"); // HACK: Add back in if debugging: if (!pointsToAdd.Contains(toAdd)) pointsToAdd.Add(toAdd); } // Create the new substroke using its drawing attributes System.Windows.Ink.DrawingAttributes drawingAttributes = stroke.DrawingAttributes; Substroke substroke = new Substroke(pointsToAdd); substroke.Name = "substroke"; substroke.Color = drawingAttributes.Color.GetHashCode(); substroke.PenTip = drawingAttributes.StylusTip.ToString(); substroke.PenWidth = (float)drawingAttributes.Width; substroke.PenHeight = (float)drawingAttributes.Height; substroke.Source = "InkSketch.canvasStrokeToSketchStroke"; substroke.Start = pointsToAdd[0].Id; substroke.End = pointsToAdd[pointsToAdd.Count - 1].Id; this.AddSubstroke(substroke); // Update the stroke's attributes this._xmlAttributes.Name = "stroke"; this._xmlAttributes.Time = (ulong)theTime; this._xmlAttributes.Type = "stroke"; this._xmlAttributes.Source = "Converter"; }
/// <summary> /// Adds the Substroke to the Stroke's Substroke ArrayList. /// Calling this repeatedly may be much slower than calling /// AddSubstrokes(list). /// </summary> /// <param name="substroke">Substroke to add</param> public void AddSubstroke(Substroke substroke) { if (substroke == null) { throw new ArgumentException("Cannot add a null substroke to a stroke!"); } AddSubstrokes(new Substroke[] { substroke }); }
public LinkedPoint(Substroke par, int index) { Point p = par.PointsL[index]; this.x = p.X; this.y = p.Y; this.parent = par; this.index = index; }
/// <summary> /// Compare this Substroke to another based on time. /// Returns less than 0 if this time is less than the other's. /// Returns 0 if this time is equal to the other's. /// Returns greater than 0 if this time is greater than the other's. /// </summary> /// <param name="obj">The other Substroke to compare this one to</param> /// <returns>An integer indicating how the Substroke times compare</returns> int System.IComparable.CompareTo(Object obj) { Substroke other = (Substroke)obj; ulong thisTime = (ulong)this.XmlAttrs.Time; ulong otherTime = (ulong)other.XmlAttrs.Time; return((int)(thisTime - otherTime)); }
/// <summary> /// Splits a Substroke at the given index. /// </summary> /// <param name="index">Index where the Substroke should be split</param> public void SplitAt(int index) { // If there is nothing to split... if (index < 1 || index > this.points.Count - 2) { return; } Substroke lastHalf = new Substroke(); // We invalidate these things this.XmlAttrs.Height = null; this.XmlAttrs.Width = null; this.XmlAttrs.Area = null; this.XmlAttrs.LeftX = null; this.XmlAttrs.TopY = null; this.XmlAttrs.X = null; this.XmlAttrs.Y = null; // Copy the rest of the attributes into the second half lastHalf.XmlAttrs = this.XmlAttrs.Clone(); lastHalf.XmlAttrs.Id = System.Guid.NewGuid(); int length = points.Count; // Add points to the last Half lastHalf.AddPoints(points.GetRange(index, length - index)); // Change the start of the last half lastHalf.XmlAttrs.Start = ((Point)lastHalf.points[0]).XmlAttrs.Id; // Remove all the points in the second half this.points.RemoveRange(index, length - index); //this.points.RemoveRange(index + 1, length - index - 1); // Used if we want to include the middle, split point in both Substrokes // Add the end to the first half this.XmlAttrs.End = ((Point)this.points[index - 1]).XmlAttrs.Id; // The new first half time is equal to the last point's time in it this.XmlAttrs.Time = ((Point)this.points[index - 1]).XmlAttrs.Time; // Update the parent info lastHalf.ParentStroke = this.parentStroke; lastHalf.ParentStroke.AddSubstroke(lastHalf); lastHalf.ParentShapes = this.parentShapes; length = lastHalf.parentShapes.Count; for (int i = 0; i < length; ++i) { if (lastHalf.parentShapes[i] != null) { ((Shape)lastHalf.parentShapes[i]).AddSubstroke(lastHalf); } } }
/// <summary> /// Removes a Substroke from the Stroke. /// </summary> /// <param name="substroke">Substroke to remove</param> /// <returns>True iff the Substroke is removed</returns> public bool RemoveSubstroke(Substroke substroke) { if (this._substrokes.Contains(substroke)) { RemoveSubstrokes(new Substroke[] { substroke }); return(true); } return(false); }
/// <summary> /// Split the substroke at the given index at the given indices /// </summary> /// <param name="substrokeIndex">The index of the substroke</param> /// <param name="pointIndices">The indices to split at</param> public void SplitSubstrokeAt(int substrokeIndex, int[] pointIndices) { // We need to step through backwards so we dont mess up the indices Array.Sort(pointIndices); Array.Reverse(pointIndices); Substroke first = (Substroke)this.substrokes[substrokeIndex]; first.SplitAt(pointIndices); }
/// <summary> /// Returns the average pressure of the points in a stroke /// </summary> /// <param name="stroke">The stroke</param> /// <returns>the average pressure</returns> public ushort findAvgPressure(Sketch.Substroke stroke) { List <Point> points = stroke.PointsL; ulong totalPressure = 0; foreach (Point p in points) { totalPressure += p.Pressure; } return((ushort)(totalPressure / ((ulong)points.Count))); }
/// <summary> /// Removes a single Substroke from the Stroke's Substroke ArrayList. /// </summary> /// <param name="substroke">The substroke to remove</param> /// <returns>True iff the substroke was successfully removed</returns> public bool RemoveSubstroke(Substroke substroke) { if (this.substrokes.Contains(substroke)) { this.substrokes.Remove(substroke); return(true); } else { return(false); } }
/// <summary> /// Removes a Substroke from the Sketch. Removes parent stroke if /// this substroke is the only substroke in the stroke. /// </summary> /// <param name="stroke">Substroke to remove</param> /// <returns>True iff Substroke is removed</returns> public bool RemoveSubstroke(Substroke substroke) { Stroke parentStroke = substroke.ParentStroke; if (parentStroke.Substrokes.Length == 1) { return(RemoveStroke(parentStroke)); } else { return(parentStroke.RemoveSubstroke(substroke)); } }
/// <summary> /// Load a Stroke with a corresponding substroke. /// Precondition: Substroke is in the Sketch/FeatureSketch. /// Postcondition: The stroke's in our bookkeeping data structures. /// </summary> /// <param name="inkStroke">The Stroke to add</param> public void AddInkStrokeWithSubstroke(System.Windows.Ink.Stroke inkStroke, Sketch.Substroke substroke) { // Format the inkStroke inkStroke.AddPropertyData(dtGuid, (ulong)DateTime.Now.ToFileTime()); String strokeId = System.Guid.NewGuid().ToString(); inkStroke.AddPropertyData(idGuid, strokeId); // Add it to the data structures (InkCanvas last) ink2sketchStr.Add(strokeId, substroke.XmlAttrs.Id); sketchStr2ink.Add(substroke.XmlAttrs.Id, strokeId); substrokeIdMap.Add(substroke.XmlAttrs.Id, substroke); mInkCanvas.Strokes.Add(inkStroke); }
/// <summary> /// Transforms (e.g. moves or resizes) an Ink Stroke in the Sketch. /// Converts the given Ink Stroke into a Sketch stroke and then /// updates the Sketch to point to the new Ink Stroke instead of the old one. /// </summary> /// <param name="iStroke">The Ink Stroke to modify</param> public void TransformInkStroke(Microsoft.Ink.Stroke iStroke) { if (!ink2sketchStr.ContainsKey(iStroke.Id)) { return; } if (!substrokeIdMap.ContainsKey(ink2sketchStr[iStroke.Id])) { return; } Sketch.Stroke newSStroke = mReadJnt.InkStroke2SketchStroke(iStroke); Substroke oldSStroke = substrokeIdMap[ink2sketchStr[iStroke.Id]]; // FIXME need to masquerade Substroke Ids. Here // we abitrarily synchronize the Ids of the first // substroke in each stroke. We do this because // ReadJnt will always return a stroke with one // substroke. In some use cases (e.g. fragmenting), // matching Ids like this might cause problems. // // Eric Peterson: June 30, 2009: When loading an old // xml sketch, we need to preserve the time data for // each point. newSStroke.Substrokes[0].XmlAttrs.Id = oldSStroke.XmlAttrs.Id; for (int i = 0; i < oldSStroke.Points.Length; i++) { newSStroke.Substrokes[0].Points[i].Time = oldSStroke.Points[i].Time; } // Update mapping between strokes ink2sketchStr.Remove(iStroke.Id); ink2sketchStr.Add(iStroke.Id, newSStroke.Substrokes[0].XmlAttrs.Id); sketchStr2ink.Remove(oldSStroke.XmlAttrs.Id); sketchStr2ink.Add(newSStroke.Substrokes[0].XmlAttrs.Id, iStroke.Id); substrokeIdMap.Remove(newSStroke.Substrokes[0].XmlAttrs.Id); substrokeIdMap.Add(newSStroke.Substrokes[0].XmlAttrs.Id, newSStroke.Substrokes[0]); // Update pointers in Sketch Sketch.Substroke newSSubstroke = newSStroke.Substrokes[0]; foreach (Sketch.Shape shape in oldSStroke.ParentShapes) { shape.AddSubstroke(newSSubstroke); } Sketch.RemoveSubstroke(oldSStroke); Sketch.AddStroke(newSStroke); }
/// <summary> /// Removes a Substroke from the Shape. /// </summary> /// <param name="substroke">Substroke to remove</param> /// <returns>True iff the Substroke is removed</returns> public bool RemoveSubstroke(Substroke substroke) { if (this.substrokes.Contains(substroke)) { substroke.ParentShapes.Remove(this); this.substrokes.Remove(substroke); UpdateSpatialAttributes(this); return(true); } else { return(false); } }
public override void Execute() { if (this.selection.Count > 0) { Sketch.Substroke selected = this.mIdToSubstroke[this.selection[0].Id] as Sketch.Substroke; if (selected != null) { FragmentDialogBox fdb = new FragmentDialogBox(new Sketch.Stroke[1] { selected.ParentStroke }); fdb.Show(); } } }
/// <summary> /// Removes an ArrayList of Substrokes from the Shape. /// </summary> /// <param name="substrokes">Substrokes to remove</param> /// <returns>True iff all Substrokes are removed</returns> public bool RemoveSubstrokes(ArrayList substrokes) { bool completelyRemoved = true; for (int i = 0; i < substrokes.Count; ++i) { Substroke currSubstroke = (Substroke)substrokes[i]; if (!RemoveSubstroke(currSubstroke)) { completelyRemoved = false; Console.WriteLine("Substroke " + currSubstroke.XmlAttrs.Id + " not removed!"); } } return(completelyRemoved); }
/// <summary> /// Called when a substroke is added to this shape, and before it is added /// to the list of substrokes. By default this does the following: /// - updates the substroke's parent shape /// - connects this shape to everything the substroke is connected to /// </summary> /// <param name="substroke">the substroke to acquire</param> protected virtual void AcquireSubstroke(Substroke substroke) { if (substroke.ParentShape != null && substroke.ParentShape != this) { throw new ArgumentException("Cannot add a substroke belonging to a different shape!"); } substroke.ParentShape = this; foreach (EndPoint endpoint in substroke.Endpoints) { Shape connected = endpoint.ConnectedShape; if (connected != null) { ConnectedShapes.Add(connected); connected.ConnectedShapes.Add(this); } } }
/// <summary> /// Refreshes the underlying data structures corresponding to the inkStroke after the /// inkStroke has been modified (moved or resized) /// </summary> /// <param name="inkStroke">The Ink Stroke to modify</param> public void UpdateInkStroke(System.Windows.Ink.Stroke inkStroke) { // Delete the old stroke but save its shape for the new Stroke Sketch.Shape oldShape = GetSketchSubstrokeByInk(inkStroke).ParentShape; DeleteStroke(inkStroke); // Add the new stroke to the Sketch and put it in the old Shape AddStroke(inkStroke); Sketch.Substroke newSubstroke = GetSketchSubstrokeByInk(inkStroke); if (oldShape != null) { oldShape.AddSubstroke(newSubstroke); if (!Sketch.ShapesL.Contains(oldShape)) { Sketch.AddShape(oldShape); } } }
/// <summary> /// Find the shortests distance from a point in this shape to a /// given point. /// </summary> /// <param name="x"></param> /// <param name="y"></param> /// <param name="exclude">If this is set, that substroke will not be considered /// when looking for close points</param> /// <returns>the shortest distance to a point in a substroke of this shape, or /// Double.MaxValue if there are no points in this substroke</returns> public double minDistanceTo(double x, double y, Substroke exclude = null) { double bestDistance = Double.MaxValue; foreach (Substroke substroke in _substrokes) { if (substroke == exclude) { continue; } double distance = substroke.minDistanceTo(x, y); if (distance < bestDistance) { bestDistance = distance; } } return(bestDistance); }
/// <summary> /// Returns the time it took to draw the substroke /// </summary> /// <param name="sub">The substroke</param> /// <returns>the total time it took to draw the substroke</returns> public ulong findSubStrokeTime(Sketch.Substroke sub) { double minTime = Double.PositiveInfinity; double maxTime = Double.NegativeInfinity; List <Point> points = sub.PointsL; foreach (Point p in points) { if ((Double)(p.Time) < minTime) { minTime = p.Time; } if ((Double)(p.Time) > maxTime) { maxTime = (Double)(p.Time); } } return((ulong)(maxTime - minTime)); }
public string Recognize(Sketch.Substroke stroke) { List <double> features = getFeatureValues(stroke.PointsL); string best = "NA"; double bestScore = double.MinValue; List <double> allScores = new List <double>(); // Compute scores for each class for (int c = 0; c < _classNames.Count; c++) { double sum = 0.0; for (int i = 0; i < _weights_0.Count; i++) { sum += _weights.GetElement(c, i) * features[i]; } double score = this._weights_0[c] + sum; allScores.Add(score); if (score > bestScore) { bestScore = score; best = _classNames[c]; } } allScores.Remove(bestScore); // Get Probability - for rejection double sumP = 0.0; foreach (double s in allScores) { sumP += Math.Exp(s - bestScore); } double probability = 1 / sumP; if (probability < SCORE_THRESHOLD) { return("Unknown"); } return(best); }
/// <summary> /// Find the parent shape of a list of strokes /// </summary> /// <param name="strokeIds"></param> /// <returns></returns> private void LabelShape(ListSet <string> strokeIds, string name) { // Create list of all shapes List <Shape> shapes = new List <Shape>(); foreach (string s in strokeIds) { Sketch.Substroke sub = sketchPanel.InkSketch.GetSketchSubstrokeByInkId(s); if (!shapes.Contains(sub.ParentShape)) { shapes.Add(sub.ParentShape); } } // Set the name to what the user specified foreach (Shape shape in shapes) { shape.Name = name; } }
/// <summary> /// Finds the features of a Substroke /// </summary> /// <param name="substroke">Substroke to find features for</param> public FeatureStroke(Sketch.Substroke substroke) { Point[] points = substroke.Points; _substroke = substroke; spatial = new Spatial(points); arcLength = new ArcLength(points); slope = new Slope(points); speed = new Speed(points); curvature = new Curvature(points, ArcLength.Profile, Slope.TanProfile); fit = new Fit(substroke); boundingBox = Compute.BoundingBox(substroke.Points); this.id = (System.Guid)substroke.Id; features = new Dictionary <string, Feature>(); featuresToUse = new Dictionary <string, bool>(); addAllFeatures(); if (UseThetas) { thetas = Compute.FindThetas(substroke.Points); //thetas = Compute.Normalize(thetas, Math.PI * 2.0); } else { thetas = new double[0]; } if (UseArcLength) { features.Add("Arc Length", new InkLength(arcLength.TotalLength)); } if (UseClosedPath) { features.Add("Part of a Closed Path", new PartOfClosedPath(false)); features.Add("Inside a Closed Path", new InsideClosedPath(false)); } }
/// <summary> /// Finds a given shape's closest endpoint to the invoking shape. /// </summary> /// <param name="otherShape">The shape with endpoints</param> /// <returns>The closest endpoint in otherShape</returns> public EndPoint ClosestEndpointFrom(Shape otherShape) { double distance = Double.MaxValue; Substroke closestSubstroke = null; EndPoint closestEndpoint = null; foreach (Substroke stroke in otherShape.Substrokes) { foreach (EndPoint endpoint in stroke.Endpoints) { double ptDist = Math.Sqrt(Math.Pow(endpoint.X - this.Centroid.X, 2) + Math.Pow(endpoint.Y - this.Centroid.Y, 2)); if (ptDist < distance) { distance = ptDist; closestSubstroke = stroke; closestEndpoint = endpoint; } } } return(closestEndpoint); }
/// <summary> /// Removes a Substroke from the Sketch. Removes parent stroke if /// this substroke is the only substroke in the stroke. /// </summary> /// <param name="substroke">Substroke to remove</param> /// <returns>True iff Substroke is removed</returns> public bool RemoveSubstroke(Substroke substroke) { Stroke parentStroke = substroke.ParentStroke; // Remove this substrokes from parent shapes // and remove all parent shapes that contain // only this substroke object[] parentShapes = substroke.ParentShapes.ToArray(); for (int i = 0; i < parentShapes.Length; ++i) { if (parentShapes[i] != null) { Shape currentShape = (Shape)parentShapes[i]; if (currentShape.Substrokes.Length == 1) { RemoveShape(currentShape); } else { currentShape.RemoveSubstroke(substroke); } } } // Remove the substroke from the parent stroke, // or, if the substroke is its parent stroke's only // child, remove the parent stroke. if (parentStroke.Substrokes.Length == 1) { return(RemoveStroke(parentStroke)); } else { return(parentStroke.RemoveSubstroke(substroke)); } }