public static List <SketchStroke> Translate(List <SketchStroke> strokes, SketchPoint origin, SketchPoint centroid) { List <SketchStroke> newStrokes = new List <SketchStroke>(); foreach (SketchStroke stroke in strokes) { List <SketchPoint> newPoints = new List <SketchPoint>(); foreach (SketchPoint point in stroke.Points) { newPoints.Add(new SketchPoint(point.X + origin.X - centroid.X, point.Y + origin.Y - centroid.Y)); } SketchStroke newStroke = new SketchStroke(newPoints, stroke.TimeStamp); newStrokes.Add(newStroke); } return(newStrokes); }
public BoundingBox(SketchStroke stroke) { MinX = double.MaxValue; MinY = double.MaxValue; MaxX = double.MinValue; MaxY = double.MinValue; foreach (SketchPoint point in stroke.Points) { MinX = MinX < point.X ? MinX : point.X; MinY = MinY < point.Y ? MinY : point.Y; MaxX = MaxX > point.X ? MaxX : point.X; MaxY = MaxY > point.Y ? MaxY : point.Y; } CenterX = (MinX + MaxX) / 2.0; CenterY = (MinY + MaxY) / 2.0; }
public static string IntersectionRelationship(SketchStroke sketchStroke1, SketchStroke sketchStroke2) { SketchPoint closestPoint = Intersection(sketchStroke1, sketchStroke2); if (closestPoint == null) { return("none"); } if (MathHelpers.EuclideanDistance(closestPoint, sketchStroke1.StartPoint) < 40) { return("touch head"); } if (MathHelpers.EuclideanDistance(closestPoint, sketchStroke1.EndPoint) < 40) { return("touch tail"); } return("cross"); }
public static List <SketchStroke> ScaleSquare(List <SketchStroke> strokes, double size) { double width = SketchFeatureExtraction.Width(strokes); double height = SketchFeatureExtraction.Height(strokes); List <SketchStroke> newStrokes = new List <SketchStroke>(); foreach (SketchStroke stroke in strokes) { List <SketchPoint> newPoints = new List <SketchPoint>(); foreach (SketchPoint point in stroke.Points) { newPoints.Add(new SketchPoint(point.X * size / width, point.Y * size / height)); } SketchStroke newStroke = new SketchStroke(newPoints, stroke.TimeStamp); newStrokes.Add(newStroke); } return(newStrokes); }
public static string[,] IntersectionMatrix(List <SketchStroke> strokes, int[] correspondance, HashSet <int> wrongDirectionStrokeIndices) { List <SketchStroke> restored = new List <SketchStroke>(); for (int i = 0; i < correspondance.Length; i++) { int strokeIndex = Array.IndexOf(correspondance, i); if (wrongDirectionStrokeIndices.Contains(strokeIndex)) { restored.Add(SketchStroke.Reverse(strokes[strokeIndex])); } else { restored.Add(strokes[strokeIndex]); } } return(IntersectionMatrix(restored)); }
public static double StartToEndSlope(SketchStroke stroke) { SketchPoint start = stroke.StartPoint; SketchPoint end = stroke.EndPoint; if (start.X == end.X) { if (end.Y >= start.Y) { return(double.PositiveInfinity); } else { return(double.NegativeInfinity); } } else { return((end.Y - start.Y) / (end.X - start.X)); } }
private void StrokeInput_StrokesCollected(InkPresenter sender, InkStrokesCollectedEventArgs args) { if (this.IsSkritter == true) { var strokes = this.WritingInkCanvas.InkPresenter.StrokeContainer.GetStrokes(); SketchStroke lastStroke = new SketchStroke(strokes[strokes.Count - 1], this.timeCollection[this.timeCollection.Count - 1]); if (SkritterHelpers.ValidateStroke(lastStroke, this.currentTemplateSketchStrokes[this.sketchStrokes.Count]) == true) { this.sketchStrokes.Add(lastStroke); InteractionTools.ShowStroke(this.AnimationCanvas, this.currentTemplateSketchStrokes[this.sketchStrokes.Count - 1]); } else { this.timeCollection.RemoveAt(this.timeCollection.Count - 1); } strokes[strokes.Count - 1].Selected = true; this.WritingInkCanvas.InkPresenter.StrokeContainer.DeleteSelected(); } }
/// <summary> /// one sample stroke contains many template strokes /// </summary> /// <param name="sample"></param> /// <param name="template"></param> /// <returns>stroke index -> list of template indices it contains</returns> public static List <List <int> > StrokeToStrokeCorrespondenceConcatenating(List <SketchStroke> sample, List <SketchStroke> template) { List <List <int> > result = new List <List <int> >(); List <KeyValuePair <SketchStroke, int> > templateStrokeToIndex = new List <KeyValuePair <SketchStroke, int> >(); for (int i = 0; i < template.Count; i++) { templateStrokeToIndex.Add(new KeyValuePair <SketchStroke, int>(template[i], i)); } foreach (SketchStroke sampleStroke in sample) { templateStrokeToIndex.Sort((t1, t2) => SketchTools.DirectedHausdorffDistance(t1.Key.Points, sampleStroke.Points).CompareTo(SketchTools.DirectedHausdorffDistance(t2.Key.Points, sampleStroke.Points))); double currHausdorffFromSampleToTemplateList = double.MaxValue; SketchStroke currConcatenated = new SketchStroke(); List <int> currListIndices = new List <int>(); foreach (KeyValuePair <SketchStroke, int> pair in templateStrokeToIndex) { SketchStroke newConcatenated = SketchStroke.ConcatenateStrokes(pair.Key, currConcatenated); double newDistance = SketchTools.HausdorffDistance(sampleStroke, newConcatenated); if (newDistance < currHausdorffFromSampleToTemplateList) { currHausdorffFromSampleToTemplateList = newDistance; currConcatenated = newConcatenated; currListIndices.Add(pair.Value); } } result.Add(currListIndices); foreach (int currIndex in currListIndices) { templateStrokeToIndex.Remove(new KeyValuePair <SketchStroke, int>(template[currIndex], currIndex)); } } return(result); }
public static async Task <Sketch> XMLToSketch(StorageFile file) { string text = await FileIO.ReadTextAsync(file); XDocument document = XDocument.Parse(text); int minX = Int32.Parse(document.Root.Attribute("frameMinX").Value); int maxX = Int32.Parse(document.Root.Attribute("frameMaxX").Value); int minY = Int32.Parse(document.Root.Attribute("frameMinY").Value); int maxY = Int32.Parse(document.Root.Attribute("frameMaxY").Value); string label = document.Root.Attribute("label").Value; List <SketchStroke> strokes = new List <SketchStroke>(); // Itereates through each stroke element foreach (XElement element in document.Root.Elements()) { // Initializes the stroke SketchStroke stroke = new SketchStroke(); // Iterates through each point element double x, y; long t; foreach (XElement pointElement in element.Elements()) { x = Double.Parse(pointElement.Attribute("x").Value); y = Double.Parse(pointElement.Attribute("y").Value); t = Int64.Parse(pointElement.Attribute("time").Value); SketchPoint point = new SketchPoint(x, y); stroke.AppendPoint(point); stroke.AppendTime(t); } strokes.Add(stroke); } return(new Sketch(minX, maxX, minY, maxY, label, strokes)); }
public static List <SketchPoint> FindCorners(SketchStroke stroke) { return(ShortStraw.FindCorners(stroke)); }
public static double PathLength(SketchStroke stroke) { return(PathLength(stroke, 0, stroke.Points.Count - 1)); }
public static bool ValidateStroke(SketchStroke sampleStroke, SketchStroke templateStroke) { return(SketchTools.HausdorffDistance(sampleStroke, templateStroke) < SkritterHelpers.StrokeValidationDistanceThreshold); }
public static SketchStroke Substroke(SketchStroke stroke, int start, int end) { return new SketchStroke(stroke.Points.GetRange(start, end - start + 1), stroke.TimeStamp.GetRange(start, end - start + 1)); }
/// <summary> /// one to one, one to many, or many to one, result is from template to sample strokes /// </summary> /// <param name="sample"></param> /// <param name="template"></param> /// <returns></returns> public static List <List <int>[]> StrokeToStrokeCorrespondenceDifferentCountStartFromSample(List <SketchStroke> sample, List <SketchStroke> template) { List <List <int>[]> result = new List <List <int>[]>(); HashSet <int> usedSampleIndices = new HashSet <int>(); HashSet <int> usedTemplateIndices = new HashSet <int>(); List <SketchStroke> sampleNormalized = SketchPreprocessing.Normalize(sample, 128, 500, new SketchPoint(0.0, 0.0)); List <SketchStroke> templateNormalized = SketchPreprocessing.Normalize(template, 128, 500, new SketchPoint(0.0, 0.0)); int si = 0; while (si < sample.Count && usedTemplateIndices.Count < template.Count) { Debug.WriteLine("si = " + si); if (usedSampleIndices.Contains(si)) { si++; continue; } double oneToOneDis = double.MaxValue; int matchedIdx = -1; for (int ti = 0; ti < template.Count; ti++) { if (usedTemplateIndices.Contains(ti)) { continue; } double dis = SketchTools.HausdorffDistance(sampleNormalized[si], templateNormalized[ti]); if (dis < oneToOneDis) { oneToOneDis = dis; matchedIdx = ti; } } usedSampleIndices.Add(si); usedTemplateIndices.Add(matchedIdx); List <int> oneToManyIndices = new List <int>(); oneToManyIndices.Add(matchedIdx); List <int> manyToOneIndices = new List <int>(); manyToOneIndices.Add(si); SketchStroke currSampleStroke = sampleNormalized[si]; double oneToManyDis = oneToOneDis; int preSample = si - 1; int postSample = si + 1; while (preSample >= 0) { if (usedSampleIndices.Contains(preSample)) { break; } SketchStroke concatenatedStroke = SketchStroke.ConcatenateStrokes(sampleNormalized[preSample], currSampleStroke); double dis = SketchTools.HausdorffDistance(concatenatedStroke, templateNormalized[matchedIdx]); if (dis < oneToManyDis) { oneToManyDis = dis; oneToManyIndices.Insert(0, preSample); currSampleStroke = concatenatedStroke; } else { break; } preSample--; } while (postSample < sample.Count) { if (usedSampleIndices.Contains(postSample)) { break; } SketchStroke concatenatedStroke = SketchStroke.ConcatenateStrokes(currSampleStroke, sampleNormalized[postSample]); double dis = SketchTools.HausdorffDistance(concatenatedStroke, templateNormalized[matchedIdx]); if (dis < oneToManyDis) { oneToManyDis = dis; oneToManyIndices.Add(postSample); currSampleStroke = concatenatedStroke; } else { break; } postSample++; } SketchStroke currTemplateStroke = templateNormalized[matchedIdx]; double manyToOneDis = oneToOneDis; int preTemplate = matchedIdx - 1; int postTemplate = matchedIdx + 1; while (preTemplate >= 0) { if (usedTemplateIndices.Contains(preTemplate)) { break; } SketchStroke concatenatedStroke = SketchStroke.ConcatenateStrokes(templateNormalized[preTemplate], currTemplateStroke); double dis = SketchTools.HausdorffDistance(concatenatedStroke, sampleNormalized[si]); if (dis < manyToOneDis) { manyToOneDis = dis; manyToOneIndices.Insert(0, preTemplate); currTemplateStroke = concatenatedStroke; } else { break; } preTemplate--; } while (postTemplate < template.Count) { if (usedTemplateIndices.Contains(postTemplate)) { break; } SketchStroke concatenatedStroke = SketchStroke.ConcatenateStrokes(currTemplateStroke, templateNormalized[postTemplate]); double dis = SketchTools.HausdorffDistance(concatenatedStroke, sampleNormalized[si]); if (dis < manyToOneDis) { manyToOneDis = dis; manyToOneIndices.Add(postTemplate); currTemplateStroke = concatenatedStroke; } else { break; } postTemplate++; } Debug.WriteLine("matched index = " + matchedIdx); int flag = -2; // -1 for oneToMany, 0 for oneToOne, 1 for manyToOne if (oneToManyDis < oneToOneDis && manyToOneDis < oneToOneDis) { if (oneToManyDis < manyToOneDis) { flag = -1; } else { flag = 1; } } else if (oneToManyDis < oneToOneDis) { flag = -1; } else if (manyToOneDis < oneToOneDis) { flag = 1; } else { flag = 0; } if (flag == 0) { List <int> oneTemplate = new List <int>(); List <int> oneSample = new List <int>(); oneTemplate.Add(matchedIdx); oneSample.Add(si); result.Add(new List <int>[] { oneTemplate, oneSample }); usedTemplateIndices.Add(matchedIdx); usedSampleIndices.Add(matchedIdx); si++; } else if (flag == -1) // one to many { List <int> one = new List <int>(); List <int> many = new List <int>(); one.Add(matchedIdx); usedTemplateIndices.Add(matchedIdx); foreach (int index in oneToManyIndices) { usedSampleIndices.Add(index); many.Add(index); } result.Add(new List <int>[] { one, many }); si = many[many.Count - 1] + 1; } else if (flag == 1) // many to one { List <int> many = new List <int>(); List <int> one = new List <int>(); foreach (int index in manyToOneIndices) { usedTemplateIndices.Add(index); many.Add(index); } one.Add(si); result.Add(new List <int>[] { many, one }); usedSampleIndices.Add(matchedIdx); si++; } } return(result); }
public static List <SketchStroke> Resample(List <SketchStroke> strokes, int n) { double totalLength = 0; foreach (SketchStroke stroke in strokes) { totalLength += SketchStrokeFeatureExtraction.PathLength(stroke); } double I = totalLength / (n - 1); double D = 0.0; List <SketchStroke> newStrokes = new List <SketchStroke>(); // Iterates through each stroke points in a list of strokes int pointCount = 0; foreach (SketchStroke stroke in strokes) { //Resamples point locations List <SketchPoint> points = stroke.Points; List <SketchPoint> newPoints = new List <SketchPoint>(); newPoints.Add(new SketchPoint(points[0].X, points[0].Y)); ++pointCount; bool isDone = false; for (int i = 1; i < points.Count; ++i) { double d = MathHelpers.EuclideanDistance(points[i - 1], points[i]); if (D + d >= I) { double qx = points[i - 1].X + ((I - D) / d) * (points[i].X - points[i - 1].X); double qy = points[i - 1].Y + ((I - D) / d) * (points[i].Y - points[i - 1].Y); if (pointCount < n - 1) { newPoints.Add(new SketchPoint(qx, qy)); ++pointCount; points.Insert(i, new SketchPoint(qx, qy)); D = 0.0; } else { isDone = true; } } else { D += d; } if (isDone) { break; } } D = 0.0; // Resamples time stamps List <long> timeStamp = stroke.TimeStamp; List <long> newTimeStamp = new List <long>(); int oldCount = timeStamp.Count; int newCount = newPoints.Count; for (int j = 0; j < newCount; ++j) { int index = (int)((double)j / newCount * oldCount); newTimeStamp.Add(timeStamp[index]); } SketchStroke newStroke = new SketchStroke(newPoints, newTimeStamp); newStrokes.Add(newStroke); } return(newStrokes); }
public static double HausdorffDistance(SketchStroke strokeA, SketchStroke strokeB) { return(SketchTools.HausdorffDistance(strokeA.Points, strokeB.Points)); }
private static bool IsLine(SketchStroke stroke) { return(IsLine(stroke, 0, stroke.Points.Count - 1)); }