Exemple #1
0
        /// <remarks>
        /// Calculates the direction in radians between this point and the given point.
        /// 0 is to the right, PI / 2 is up, etc.
        ///
        /// @param comparePoint the point to get the direction to from this point
        /// @return the direction in radians between this point and the given point.
        /// </remarks>
        public double GetDirection(WrittenPoint comparePoint)
        {
            double dx = X - comparePoint.X;
            double dy = Y - comparePoint.Y;

            return(Math.PI - Math.Atan2(dy, dx));
        }
Exemple #2
0
        /// <remarks>
        /// Calculates the direction in radians between this point and the given point.
        /// 0 is to the right, PI / 2 is up, etc.
        /// 
        /// @param comparePoint the point to get the direction to from this point
        /// @return the direction in radians between this point and the given point.
        /// </remarks>
        public double GetDirection(WrittenPoint comparePoint)
        {
            double dx = X - comparePoint.X;
            double dy = Y - comparePoint.Y;

            return Math.PI - Math.Atan2(dy, dx);
        }
Exemple #3
0
        public double Distance(WrittenPoint comparePoint)
        {
            double dx = X - comparePoint.X;
            double dy = Y - comparePoint.Y;

            return(Math.Sqrt(dx * dx + dy * dy));
        }
Exemple #4
0
        public List <SubStrokeDescriptor> GetSubStrokes(double charWidth, double charHeight)
        {
            if (!this.isAnalyzed)
            {
                this.AnalyzeAndMark();
            }

            List <SubStrokeDescriptor> subStrokes = new List <SubStrokeDescriptor>();

            // Any WrittenStroke should have at least two points, (a single point cannot constitute a Stroke).
            // We should therefore be safe calling an iterator without checking for the first point.
            WrittenPoint previousPoint = pointList[0];

            for (int i = 1; i != pointList.Count; ++i)
            {
                WrittenPoint nextPoint = pointList[i];

                if (nextPoint.IsPivot)
                {
                    // The direction from each previous point to each successive point, in radians.
                    double direction = previousPoint.GetDirection(nextPoint);

                    // Use the normalized length, to account for relative character size.
                    double normalizedLength = previousPoint.GetDistanceNormalized(nextPoint, charWidth, charHeight);

                    SubStrokeDescriptor subStroke = new SubStrokeDescriptor(direction, normalizedLength);
                    subStrokes.Add(subStroke);

                    previousPoint = nextPoint;
                }
            }

            return(subStrokes);
        }
Exemple #5
0
        public void AddPoint(WrittenPoint point,
            ref double charLeftX, ref double charRightX,
            ref double charTopY, ref double charBottomY)
        {
            int pointX = point.X;
            int pointY = point.Y;

            // Expand the bounding box coordinates for this WrittenCharacter in necessary.
            charLeftX = Math.Min(pointX, charLeftX);
            charRightX = Math.Max(pointX, charRightX);
            charTopY = Math.Min(pointY, charTopY);
            charBottomY = Math.Max(pointY, charBottomY);

            this.pointList.Add(point);
        }
Exemple #6
0
        public void AddPoint(WrittenPoint point,
                             ref double charLeftX, ref double charRightX,
                             ref double charTopY, ref double charBottomY)
        {
            int pointX = point.X;
            int pointY = point.Y;

            // Expand the bounding box coordinates for this WrittenCharacter in necessary.
            charLeftX   = Math.Min(pointX, charLeftX);
            charRightX  = Math.Max(pointX, charRightX);
            charTopY    = Math.Min(pointY, charTopY);
            charBottomY = Math.Max(pointY, charBottomY);

            this.pointList.Add(point);
        }
Exemple #7
0
        /// <remarks>
        /// Normalized length takes into account the size of the WrittenCharacter on the canvas.
        /// For example, if the WrittenCharacter was written small in the upper left portion of the canvas,
        /// then the lengths not be based on the full size of the canvas, but rather only on the relative
        /// size of the WrittenCharacter.
        ///
        /// @param comparePoint the point to get the normalized distance to from this point
        ///
        /// @return the normalized length from this point to the compare point
        /// </remarks>
        public double GetDistanceNormalized(WrittenPoint comparePoint,
                                            double charWidth, double charHeight)
        {
            double width  = (double)charWidth;
            double height = (double)charHeight;

            // normalizer is a diagonal along a square with sides of size the larger dimension of the bounding box
            double dimensionSquared = width > height ? width * width : height * height;
            double normalizer       = Math.Sqrt(dimensionSquared + dimensionSquared);

            double distanceNormalized = Distance(comparePoint) / normalizer;

            // shouldn't be longer than 1 if it's normalized
            distanceNormalized = Math.Min(distanceNormalized, 1.0);

            return(distanceNormalized);
        }
Exemple #8
0
        /// <remarks>
        /// Normalized length takes into account the size of the WrittenCharacter on the canvas.
        /// For example, if the WrittenCharacter was written small in the upper left portion of the canvas,
        /// then the lengths not be based on the full size of the canvas, but rather only on the relative
        /// size of the WrittenCharacter.
        /// 
        /// @param comparePoint the point to get the normalized distance to from this point
        /// 
        /// @return the normalized length from this point to the compare point
        /// </remarks>
        public double GetDistanceNormalized(WrittenPoint comparePoint,
            double charWidth, double charHeight)
        {
            double width = (double)charWidth;
            double height = (double)charHeight;

            // normalizer is a diagonal along a square with sides of size the larger dimension of the bounding box
            double dimensionSquared = width > height ? width * width : height * height;
            double normalizer = Math.Sqrt(dimensionSquared + dimensionSquared);

            double distanceNormalized = Distance(comparePoint) / normalizer;

            // shouldn't be longer than 1 if it's normalized
            distanceNormalized = Math.Min(distanceNormalized, 1.0);

            return distanceNormalized;
        }
Exemple #9
0
        /// <summary>
        /// Start recognizing a character in a BG thread after strokes have changed.
        /// </summary>
        private void startNewCharRecog(IEnumerable<WritingPad.Stroke> strokes)
        {
            // If there are other matchers running, stop them now
            lock (runningMatchers)
            {
                foreach (StrokesMatcher sm in runningMatchers) sm.Stop();
            }
            // Convert stroke data to HanziLookup's format
            WrittenCharacter wc = new WrittenCharacter();
            foreach (WritingPad.Stroke stroke in strokes)
            {
                WrittenStroke ws = new WrittenStroke();
                foreach (PointF p in stroke.Points)
                {
                    WrittenPoint wp = new WrittenPoint((int)(p.X), (int)(p.Y));
                    ws.AddPoint(wp, ref wc.LeftX, ref wc.RightX, ref wc.TopY, ref wc.BottomY);
                }
                wc.AddStroke(ws);
            }
            if (wc.StrokeList.Count == 0)
            {
                // Don't bother doing anything if nothing has been input yet (number of strokes == 0).
                ctrlCharPicker.SetItems(null);
                return;
            }

            ThreadPool.QueueUserWorkItem(recognize, wc);
        }
Exemple #10
0
 public double Distance(WrittenPoint comparePoint)
 {
     double dx = X - comparePoint.X;
     double dy = Y - comparePoint.Y;
     return Math.Sqrt(dx * dx + dy * dy);
 }
Exemple #11
0
        /// <summary>
        /// Analyzes the given WrittenStroke and marks its constituent WrittenPoints to demarcate the SubStrokes.
        /// Points that demarcate between the SubStroke segments are marked as pivot points.
        /// These pivot points can later be used to build up a List of SubStroke objects.
        /// </summary>
        public void AnalyzeAndMark()
        {
            var pointIter = pointList.GetEnumerator();

            // It should be impossible for a stroke to have < 2 points, so we are safe calling next() twice.
            pointIter.MoveNext();
            WrittenPoint firstPoint    = pointIter.Current;
            WrittenPoint previousPoint = firstPoint;

            pointIter.MoveNext();
            WrittenPoint pivotPoint = pointIter.Current;

            // The first point of a Stroke is always a pivot point.
            firstPoint.IsPivot = true;
            int subStrokeIndex = 1;

            // The first point and the next point are always part of the first SubStroke.
            firstPoint.SubStrokeIndex = subStrokeIndex;
            pivotPoint.SubStrokeIndex = subStrokeIndex;

            // localLength keeps track of the immediate distance between the latest three points.
            // We can use the localLength to find an abrupt change in SubStrokes, such as at a corner.
            // We do this by checking localLength against the distance between the first and last
            // of the three points.  If localLength is more than a certain amount longer than the
            // length between the first and last point, then there must have been a corner of some kind.
            double localLength = firstPoint.Distance(pivotPoint);

            // runningLength keeps track of the length between the start of the current SubStroke
            // and the point we are currently examining.  If the runningLength becomes a certain
            // amount longer than the straight distance between the first point and the current
            // point, then there is a new SubStroke.  This accounts for a more gradual change
            // from one SubStroke segment to another, such as at a longish curve.
            double runningLength = localLength;

            // Iterate over the points, marking the appropriate ones as pivots.
            while (pointIter.MoveNext())
            {
                WrittenPoint nextPoint = pointIter.Current;

                // pivotPoint is the point we're currently examining to see if it's a pivot.
                // We get the distance between this point and the next point and add it
                // to the length sums we're using.
                double pivotLength = pivotPoint.Distance(nextPoint);
                localLength   += pivotLength;
                runningLength += pivotLength;

                // Check the lengths against the ratios.  If the lengths are a certain among
                // longer than a straight line between the first and last point, then we
                // mark the point as a pivot.
                double distFromPrevious = previousPoint.Distance(nextPoint);
                double distFromFirst    = firstPoint.Distance(nextPoint);
                if (localLength > MAX_LOCAL_LENGTH_RATIO * distFromPrevious ||
                    runningLength > MAX_RUNNING_LENGTH_RATIO * distFromFirst)
                {
                    if (previousPoint.IsPivot && previousPoint.Distance(pivotPoint) < MIN_SEGMENT_LENGTH)
                    {
                        // If the previous point was a pivot and was very close to this point,
                        // which we are about to mark as a pivot, then unmark the previous point as a pivot.
                        // Also need to decrement the SubStroke that it belongs to since it's not part of
                        // the new SubStroke that begins at this pivot.
                        previousPoint.IsPivot        = false;
                        previousPoint.SubStrokeIndex = subStrokeIndex - 1;
                    }
                    else
                    {
                        // If we didn't have to unmark a previous pivot, then the we can increment the SubStrokeIndex.
                        // If we did unmark a previous pivot, then the old count still applies and we don't need to increment.
                        subStrokeIndex++;
                    }

                    pivotPoint.IsPivot = true;

                    // A new SubStroke has begun, so the runningLength gets reset.
                    runningLength = pivotLength;

                    firstPoint = pivotPoint;
                }

                localLength = pivotLength;                              // Always update the localLength, since it deals with the last three seen points.

                previousPoint = pivotPoint;
                pivotPoint    = nextPoint;

                pivotPoint.SubStrokeIndex = subStrokeIndex;
            }

            // last point (currently referenced by pivotPoint) has to be a pivot
            pivotPoint.IsPivot = true;

            // Point before the final point may need to be handled specially.
            // Often mouse action will produce an unintended small segment at the end.
            // We'll want to unmark the previous point if it's also a pivot and very close to the lat point.
            // However if the previous point is the first point of the stroke, then don't unmark it, because then we'd only have one pivot.
            if (previousPoint.IsPivot &&
                previousPoint.Distance(pivotPoint) < MIN_SEGMENT_LENGTH &&
                previousPoint != this.pointList[0])
            {
                previousPoint.IsPivot     = false;
                pivotPoint.SubStrokeIndex = subStrokeIndex - 1;
            }

            // Mark the stroke as analyzed so that it won't need to be analyzed again.
            this.isAnalyzed = true;
        }