예제 #1
0
        /**
         * A common helper method to initialize a table of precomputed score values using a cubic curve
         * @param curve the curve
         * @param numSamples the number of samples to compute
         * @return the score array table
         */
        static private double[] initCubicCurveScoreTable(CubicCurve2D curve, int numSamples)
        {
            double x1 = curve.X1;
            double x2 = curve.X2;

            double range = x2 - x1;

            double x    = x1;
            double xInc = range / numSamples;  // even incrementer to increment x value by when sampling across the curve

            double[] scoreTable = new double[numSamples];

            // For use to pass into with solveCubicCurve
            double[] solutions = new double[1];

            // Sample evenly across the curve and set the samples into the table.
            for (int i = 0; i < numSamples; i++)
            {
                //CurveUtils.solveCubicCurveForX(curve, Math.Min(x, x2), solutions);
                //double t = solutions[0];
                double t = curve.GetFirstSolutionForX(Math.Min(x, x2));
                //scoreTable[i] = CurveUtils.getPointOnCubicCurve(curve, t).getY();
                scoreTable[i] = curve.GetYOnCurve(t);


                x += xInc;
            }

            return(scoreTable);
        }
예제 #2
0
        /**
         * Computes the range of substrokes to use when computing matches based on looseness.
         * When matching, sub strokes are matched up with one another to find the best
         * matching.  But if two substrokes are +/-  beyond this range, then the comparison
         * is short-circuited for some computation savings.
         *
         * @param subStrokeCount the substroke count of the input character
         * @param looseness the looseness, 0-1
         * @return the range
         */
        private int getSubStrokesRange(int subStrokeCount)
        {
            // Return the maximum if looseness = 1.0.
            // Otherwise we'd have to ensure that the floating point value led to exactly the right int count.
            if (looseness == 1.0)
            {
                return(CharacterDescriptor.MAX_CHARACTER_SUB_STROKE_COUNT);
            }

            // We use a CubicCurve that grows slowly at first and then rapidly near the end to the maximum.

            double y0 = subStrokeCount * 0.25;

            double ctrl1X = 0.4;
            double ctrl1Y = 1.5 * y0;

            double ctrl2X = 0.75;
            double ctrl2Y = 1.5 * ctrl1Y;

            double[]     solutions = new double[1];
            CubicCurve2D curve     = new CubicCurve2D(0, y0, ctrl1X, ctrl1Y, ctrl2X, ctrl2Y, 1, CharacterDescriptor.MAX_CHARACTER_SUB_STROKE_COUNT);
            //CurveUtils.solveCubicCurveForX(curve, looseness, solutions);
            //double t = solutions[0];
            double t = curve.GetFirstSolutionForX(looseness);

            // We get the t value on the parametrized curve where the x value matches the looseness.
            // Then we compute the y value for that t.  This gives the range.

            //return (int)Math.Round(CurveUtils.getPointOnCubicCurve(curve, t).getY());
            return((int)Math.Round(curve.GetYOnCurve(t)));
        }
예제 #3
0
        /**
         * Computes a range of strokes to use based on the given looseness.
         * Only characters whose number of strokes are within the input number of strokes
         * +/- this range will be considered during comparison.  This helps cut down
         * on matching cost.
         *
         * @param strokeCount the number of input strokes
         * @param looseness the looseness, 0-1
         * @return the range
         */
        private int getStrokesRange(int strokeCount)
        {
            // Just return some extreme values if at minimum or maximum.
            // Helps to avoid possible floating point issues when near the extremes.
            if (looseness == 0.0)
            {
                return(0);
            }
            else if (looseness == 1.0)
            {
                return(CharacterDescriptor.MAX_CHARACTER_STROKE_COUNT);
            }

            // We use a CubicCurve that grows slowly at first and then rapidly near the end to the maximum.
            // This is so a looseness at or near 1.0 will return a range that will consider all characters.

            double ctrl1X = 0.35;
            double ctrl1Y = strokeCount * 0.4;

            double ctrl2X = 0.6;
            double ctrl2Y = strokeCount;

            double[]     solutions = new double[1];
            CubicCurve2D curve     = new CubicCurve2D(0, 0, ctrl1X, ctrl1Y, ctrl2X, ctrl2Y, 1, CharacterDescriptor.MAX_CHARACTER_STROKE_COUNT);
            //CurveUtils.solveCubicCurveForX(curve, looseness, solutions);
            //double t = solutions[0];
            double t = curve.GetFirstSolutionForX(looseness);

            // We get the t value on the parametrized curve where the x value matches the looseness.
            // Then we compute the y value for that t.  This gives the range.

            //return (int)Math.Round(CurveUtils.getPointOnCubicCurve(curve, t).getY());
            return((int)Math.Round(curve.GetYOnCurve(t)));
        }
예제 #4
0
        /**
         * Builds a precomputed array of values to use when getting the score between two substroke directions.
         * Two directions should differ by 0 - Pi, and the score should be the (difference / Pi) * score table's length
         *
         * @return the direction score table
         */
        static private double[] initDirectionScoreTable()
        {
            // The curve drops as the difference grows, but rises again some at the end because
            // a stroke that is 180 degrees from the expected direction maybe OK passable.
            CubicCurve2D curve = new CubicCurve2D(0, 1.0, 0.5, 1.0, 0.25, -2.0, 1.0, 1.0);

            return(initCubicCurveScoreTable(curve, 100));
        }
예제 #5
0
        /**
         * Builds a precomputed array of values to use when getting the score between two substroke lengths.
         * A ratio less than one is computed for the two lengths, and the score should be the ratio * score table's length.
         *
         * @return the length score table
         */
        static private double[] initLengthScoreTable()
        {
            // Curve grows rapidly as the ratio grows and levels off quickly.
            // This is because we don't really expect lengths to vary a lot.
            // We are really just trying to distinguish between tiny strokes and long strokes.
            CubicCurve2D curve = new CubicCurve2D(0, 0, 0.25, 1.0, 0.75, 1.0, 1.0, 1.0);

            return(initCubicCurveScoreTable(curve, 100));
        }