public static double Distance(PointR p1, PointR p2)
        {
            double dx = p2.X - p1.X;
            double dy = p2.Y - p1.Y;

            return(Math.Sqrt(dx * dx + dy * dy));
        }
        // rotate the points by the given radians about their centroid
        public static List <PointR> RotateByRadians(List <PointR> points, double radians)
        {
            List <PointR> newPoints = new List <PointR>(points.Count);
            PointR        c         = Centroid(points);

            double cos = Math.Cos(radians);
            double sin = Math.Sin(radians);

            double cx = c.X;
            double cy = c.Y;

            for (int i = 0; i < points.Count; i++)
            {
                PointR p = (PointR)points[i];

                double dx = p.X - cx;
                double dy = p.Y - cy;

                PointR q = PointR.Empty;
                q.X = dx * cos - dy * sin + cx;
                q.Y = dx * sin + dy * cos + cy;

                newPoints.Add(q);
            }
            return(newPoints);
        }
        // scales the points so that they form the size given. does not restore the
        // origin of the box.
        // adapted from ScaleTo() to smartly handle 1D scaling -- ie, if a gesture is 1D,
        // scale to the longer dimension only, or we warp our gestures too much
        // Lisa 12/28/2007
        public static List <PointR> ScaleTo1D(List <PointR> points, SizeR sz)
        {
            List <PointR> newPoints = new List <PointR>(points.Count);
            RectangleR    r         = FindBox(points);

            // scale both by same factor
            double scaleFactor = 0.0;

            if (r.Width > r.Height)
            {
                scaleFactor = r.Width;
            }
            else
            {
                scaleFactor = r.Height;
            }

            for (int i = 0; i < points.Count; i++)
            {
                PointR p = (PointR)points[i];
                if (r.Width != 0d)
                {
                    p.X *= (sz.Width / scaleFactor);
                }

                if (r.Height != 0d)
                {
                    p.Y *= (sz.Height / scaleFactor);
                }
                newPoints.Add(p);
            }
            return(newPoints);
        }
        // new scaling methods rewritten by Lisa as of 8/9/2009 from input from Jake
        public static List <PointR> Scale(List <PointR> pts, double oneDRatio, SizeR size) // scales the oriented bbox based on 1D or 2D
        {
            if (NDollarParameters.Instance.UseUniformScaling)                              // scale to a uniform circle
            {
                // do new thing
                PointR centroid      = Utils.Centroid(pts);
                double radiusSquared = 1.0d;
                foreach (PointR point in pts)
                {
                    double distanceSquared = Math.Pow((centroid.X - point.X), 2.0) + Math.Pow((centroid.Y - point.Y), 2.0);
                    if (distanceSquared > radiusSquared)
                    {
                        radiusSquared = distanceSquared;
                    }
                }

                double factor = size.Width / Math.Sqrt(radiusSquared); //Assume that size is a square and arbitrarily select width
                                                                       //this could also be replaced with a constant value (250?)

                List <PointR> scaledPts = new List <PointR>();
                for (int i = 0; i < pts.Count; i++)
                {
                    PointR p = new PointR((PointR)pts[i]);
                    p.X *= factor;
                    p.Y *= factor;
                    scaledPts.Add(p);
                }
                return(scaledPts);
            }
            else // do old thing
            {
                return(Utils.ScaleByDimension(pts, oneDRatio, size));
            }
        }
        public Gesture(List <PointR> points)
        {
            this.Name      = String.Empty;
            this.RawPoints = new List <PointR>(points);

            Points = RawPoints;

            Points = Utils.Resample(Points, 64);

            double radians = Utils.AngleInRadians(Utils.Centroid(Points), (PointR)Points[0], false);

            Points = Utils.RotateByRadians(Points, -radians);

            this.Is1D = Utils.Is1DGesture(RawPoints);

            Points = Utils.Scale(Points, 0.3f, new SizeR(250, 250));

            // next, if NOT rotation-invariant, rotate back
            if (!NDollarParameters.Instance.RotationInvariant)
            {
                Points = Utils.RotateByRadians(Points, +radians); // undo angle
            }

            Points = Utils.TranslateCentroidTo(Points, new PointR(0, 0));

            this.StartUnitVector = Utils.CalcStartUnitVector(Points, 8);

            this.VectorVersion = Vectorize(this.Points);
        }
        // determines the angle, in radians, between two points. the angle is defined
        // by the circle centered on the start point with a radius to the end point,
        // where 0 radians is straight right from start (+x-axis) and PI/2 radians is
        // straight down (+y-axis).
        public static double AngleInRadians(PointR start, PointR end, bool positiveOnly)
        {
            double radians = 0.0;

            if (start.X != end.X)
            {
                radians = Math.Atan2(end.Y - start.Y, end.X - start.X);
            }
            else // pure vertical movement
            {
                if (end.Y < start.Y)
                {
                    radians = -Math.PI / 2.0; // -90 degrees is straight up
                }
                else if (end.Y > start.Y)
                {
                    radians = Math.PI / 2.0; // 90 degrees is straight down
                }
            }
            if (positiveOnly && radians < 0.0)
            {
                radians += Math.PI * 2.0;
            }
            return(radians);
        }
 // copy constructor
 public PointR(PointR p)
 {
     X = p.X;
     Y = p.Y;
     T = p.T;
     P = p.P;
 }
        // Rotate a point 'p' around a point 'c' by the given radians.
        // Rotation (around the origin) amounts to a 2x2 matrix of the form:
        //
        //		[ cos A		-sin A	] [ p.x ]
        //		[ sin A		cos A	] [ p.y ]
        //
        // Note that the C# Math coordinate system has +x-axis stright right and
        // +y-axis straight down. Rotation is clockwise such that from +x-axis to
        // +y-axis is +90 degrees, from +x-axis to -x-axis is +180 degrees, and
        // from +x-axis to -y-axis is -90 degrees.
        public static PointR RotatePoint(PointR p, PointR c, double radians)
        {
            PointR q = PointR.Empty;

            q.X = (p.X - c.X) * Math.Cos(radians) - (p.Y - c.Y) * Math.Sin(radians) + c.X;
            q.Y = (p.X - c.X) * Math.Sin(radians) + (p.Y - c.Y) * Math.Cos(radians) + c.Y;
            return(q);
        }
 public override bool Equals(object obj)
 {
     if (obj is PointR)
     {
         PointR p = (PointR)obj;
         return(X == p.X && Y == p.Y);
     }
     return(false);
 }
        // translates the points by the given delta amounts
        public static List <PointR> TranslateBy(List <PointR> points, SizeR sz)
        {
            List <PointR> newPoints = new List <PointR>(points.Count);

            for (int i = 0; i < points.Count; i++)
            {
                PointR p = (PointR)points[i];
                p.X += sz.Width;
                p.Y += sz.Height;
                newPoints.Add(p);
            }
            return(newPoints);
        }
        // scales the points so that the length of their shorter side
        // matches the length of the shorter side of the given box.
        // thus, both dimensions are warped proportionally, rather than
        // independently, like in the function ScaleTo.
        public static List <PointR> ScaleToMin(List <PointR> points, RectangleR box)
        {
            List <PointR> newPoints = new List <PointR>(points.Count);
            RectangleR    r         = FindBox(points);

            for (int i = 0; i < points.Count; i++)
            {
                PointR p = (PointR)points[i];
                p.X *= (box.MinSide / r.MinSide);
                p.Y *= (box.MinSide / r.MinSide);
                newPoints.Add(p);
            }
            return(newPoints);
        }
        // scales by the percentages contained in the 'sz' parameter. values of 1.0 would result in the
        // identity scale (that is, no change).
        public static List <PointR> ScaleBy(List <PointR> points, SizeR sz)
        {
            List <PointR> newPoints = new List <PointR>(points.Count);
            RectangleR    r         = FindBox(points);

            for (int i = 0; i < points.Count; i++)
            {
                PointR p = (PointR)points[i];
                p.X *= sz.Width;
                p.Y *= sz.Height;
                newPoints.Add(p);
            }
            return(newPoints);
        }
        // translates the points so that their centroid lies at 'toPt'
        public static List <PointR> TranslateCentroidTo(List <PointR> points, PointR toPt)
        {
            List <PointR> newPoints = new List <PointR>(points.Count);
            PointR        centroid  = Centroid(points);

            for (int i = 0; i < points.Count; i++)
            {
                PointR p = (PointR)points[i];
                p.X += (toPt.X - centroid.X);
                p.Y += (toPt.Y - centroid.Y);
                newPoints.Add(p);
            }
            return(newPoints);
        }
        // translates the points so that the upper-left corner of their bounding box lies at 'toPt'
        public static List <PointR> TranslateBBoxTo(List <PointR> points, PointR toPt)
        {
            List <PointR> newPoints = new List <PointR>(points.Count);
            RectangleR    r         = Utils.FindBox(points);

            for (int i = 0; i < points.Count; i++)
            {
                PointR p = (PointR)points[i];
                p.X += (toPt.X - r.X);
                p.Y += (toPt.Y - r.Y);
                newPoints.Add(p);
            }
            return(newPoints);
        }
        // Calculate the angle from the initial point of the array of Points (points[0])
        // to points[index].
        //
        // Returns this angle represented by a unit vector (stored in a Point).
        //
        // **This is used in Gesture.cs:Gesture() to compute the start angle in support
        // of the optimization to not compare candidates to templates whose start angles
        // are widely different. Lisa 8/8/2009
        public static PointR CalcStartUnitVector(List <PointR> points, int index)
        {
            // v is the vector from points[0] to points[index]
            PointR v = new PointR(((PointR)points[index]).X - ((PointR)points[0]).X,
                                  ((PointR)points[index]).Y - ((PointR)points[0]).Y);

            // len is the length of vector v
            double len = Math.Sqrt(v.X * v.X + v.Y * v.Y);

            // the unit vector representing the angle between points[0] and points[index]
            // is the vector v divided by its length len
            // TODO: does there need to be a divide by zero check?
            return(new PointR(v.X / len, v.Y / len));
        }
        // will return result in radians
        public static double AngleBetweenUnitVectors(PointR v1, PointR v2) // gives acute angle between unit vectors from (0,0) to v1, and (0,0) to v2
        {
            // changed this method on 9/28/2009, Lisa
            double test = v1.X * v2.X + v1.Y * v2.Y; // arc cosine of the vector dot product

            // sometimes these two cases can happen because of rounding error in the dot product calculation
            if (test < -1.0)
            {
                test = -1.0; // truncate rounding errors
            }
            if (test > 1.0)
            {
                test = 1.0; // truncate rounding errors
            }
            return(Math.Acos(test));
        }
        // scales the points so that they form the size given. does not restore the
        // origin of the box.
        public static List <PointR> ScaleTo(List <PointR> points, SizeR sz)
        {
            List <PointR> newPoints = new List <PointR>(points.Count);
            RectangleR    r         = FindBox(points);

            for (int i = 0; i < points.Count; i++)
            {
                PointR p = (PointR)points[i];
                if (r.Width != 0d)
                {
                    p.X *= (sz.Width / r.Width);
                }

                if (r.Height != 0d)
                {
                    p.Y *= (sz.Height / r.Height);
                }
                newPoints.Add(p);
            }
            return(newPoints);
        }
Exemple #18
0
        private List <PointR> ResampleBetweenPoints(List <PointR> points)
        {
            var           I     = PathLength(points) / (NUMRESAMPLEPOINTS - 1);
            double        bigD  = 0;
            List <PointR> v     = new List <PointR>();
            var           prevP = points[0];

            for (int i = 1; i < points.Count; i++)
            {
                var thisPoint = points[i];
                var prevPoint = points[i - 1];
                var pDist     = Distance(thisPoint, prevPoint);

                if (bigD + pDist > I)
                {
                    var    qx = points[i - 1].X + (points[i].X - points[i - 1].X) * (I - bigD) / pDist;
                    var    qy = points[i - 1].Y + (points[i].Y - points[i - 1].Y) * (I - bigD) / pDist;
                    PointR q  = new PointR(qx, qy);

                    var rx = q.X - prevP.X;
                    var ry = q.Y - prevP.Y;
                    var r  = new PointR(rx, ry);
                    var rd = Distance(new PointR(0, 0), r);
                    r.X = rx / rd;
                    r.Y = ry / rd;

                    bigD  = 0;
                    prevP = q;

                    v.Add(r);
                    points.Insert(i, q);
                }
                else
                {
                    bigD = bigD + pDist;
                }
            }
            return(v);
        }
Exemple #19
0
        public static List <PointR> pennyPincherResample(List <PointR> points, int numberOfPoints = 32)
        {
            double        I      = getStrokeLength(points) / (numberOfPoints - 1); // interval length
            double        D      = 0.0;
            List <PointR> srcPts = new List <PointR>(points);
            List <PointR> vector = new List <PointR>(numberOfPoints);

            PointR prev = srcPts[0];

            for (int i = 1; i < srcPts.Count; i++)
            {
                PointR pt1 = (PointR)srcPts[i - 1];
                PointR pt2 = (PointR)srcPts[i];

                double d = getDistanceBetween(pt1, pt2);
                if ((D + d) >= I)
                {
                    double qx = pt1.X + ((I - D) / d) * (pt2.X - pt1.X);
                    double qy = pt1.Y + ((I - D) / d) * (pt2.Y - pt1.Y);
                    PointR q  = new PointR(qx, qy);
                    PointR r  = new PointR(qx - prev.X, qy - prev.Y);
                    double rd = getDistanceBetween(new PointR(0, 0), r);
                    PointR rr = new PointR(r.X / rd, r.Y / rd);
                    vector.Add(rr);      // append new vector 'rr'
                    srcPts.Insert(i, q); // insert 'q' at position i in points s.t. 'q' will be the next i
                    D    = 0.0;
                    prev = q;
                }
                else
                {
                    D += d;
                }
            }

            return(vector);
        }
        public static List <PointR> Resample(List <PointR> points, int n)
        {
            double        I      = PathLength(points) / (n - 1); // interval length
            double        D      = 0.0;
            List <PointR> srcPts = new List <PointR>(points);
            List <PointR> dstPts = new List <PointR>(n);

            dstPts.Add(srcPts[0]);
            for (int i = 1; i < srcPts.Count; i++)
            {
                PointR pt1 = (PointR)srcPts[i - 1];
                PointR pt2 = (PointR)srcPts[i];

                double d = Distance(pt1, pt2);
                if ((D + d) >= I)
                {
                    double qx = pt1.X + ((I - D) / d) * (pt2.X - pt1.X);
                    double qy = pt1.Y + ((I - D) / d) * (pt2.Y - pt1.Y);
                    PointR q  = new PointR(qx, qy);
                    dstPts.Add(q);       // append new point 'q'
                    srcPts.Insert(i, q); // insert 'q' at position i in points s.t. 'q' will be the next i
                    D = 0.0;
                }
                else
                {
                    D += d;
                }
            }
            // somtimes we fall a rounding-error short of adding the last point, so add it if so
            if (dstPts.Count == n - 1)
            {
                dstPts.Add(srcPts[srcPts.Count - 1]);
            }

            return(dstPts);
        }
Exemple #21
0
 private double Distance(PointR p1, PointR p2)
 {
     return(Math.Sqrt(Math.Pow((p2.X - p1.X), 2) + Math.Pow((p2.Y - p1.Y), 2)));
 }
Exemple #22
0
 // get distance of two points
 public static double getDistanceBetween(PointR p1, PointR p2)
 {
     return(Math.Sqrt(Math.Pow(Math.Abs(p1.X - p2.X), 2) + Math.Pow(Math.Abs(p1.Y - p2.Y), 2)));
 }
        // determines the angle, in degrees, between two points. the angle is defined
        // by the circle centered on the start point with a radius to the end point,
        // where 0 degrees is straight right from start (+x-axis) and 90 degrees is
        // straight down (+y-axis).
        public static double AngleInDegrees(PointR start, PointR end, bool positiveOnly)
        {
            double radians = AngleInRadians(start, end, positiveOnly);

            return(Rad2Deg(radians));
        }