public Vector(PointF pt)
 {
     _x = pt.X;
     _y = pt.Y;
 }
 public Vector(PointF st, PointF end)
 {
     _x = end.X - st.X;
     _y = end.Y - st.Y;
 }
        ActualImage GetTransformedBilinearInterpolation()
        {
            //4 points sampling
            //weight between four point
            ActualImage destCB = new ActualImage(rect.Width, rect.Height, PixelFormat.ARGB32);
            MyImageReaderWriter destWriter = new MyImageReaderWriter();
            destWriter.ReloadImage(destCB);
            PointF ptInPlane = new PointF();
            int x1, x2, y1, y2;
            double dab, dbc, dcd, dda;
            float dx1, dx2, dy1, dy2, dx1y1, dx1y2, dx2y1, dx2y2;
            int rectWidth = rect.Width;
            int rectHeight = rect.Height;
            var ab_vec = this.AB;
            var bc_vec = this.BC;
            var cd_vec = this.CD;
            var da_vec = this.DA;
            int rectLeft = this.rect.Left;
            int rectTop = this.rect.Top;
            for (int y = 0; y < rectHeight; ++y)
            {
                for (int x = 0; x < rectWidth; ++x)
                {
                    PointF srcPt = new PointF(x, y);
                    srcPt.Offset(rectLeft, rectTop);
                    if (!IsOnPlaneABCD(srcPt))
                    {
                        continue;
                    }
                    //-------------------------------------
                    dab = Math.Abs(new Vector(vertex[0], srcPt).CrossProduct(ab_vec));
                    dbc = Math.Abs(new Vector(vertex[1], srcPt).CrossProduct(bc_vec));
                    dcd = Math.Abs(new Vector(vertex[2], srcPt).CrossProduct(cd_vec));
                    dda = Math.Abs(new Vector(vertex[3], srcPt).CrossProduct(da_vec));
                    ptInPlane.X = (float)(srcW * (dda / (dda + dbc)));
                    ptInPlane.Y = (float)(srcH * (dab / (dab + dcd)));
                    x1 = (int)ptInPlane.X;
                    y1 = (int)ptInPlane.Y;
                    if (x1 >= 0 && x1 < srcW && y1 >= 0 && y1 < srcH)
                    {
                        //bilinear interpolation *** 
                        x2 = (x1 == srcW - 1) ? x1 : x1 + 1;
                        y2 = (y1 == srcH - 1) ? y1 : y1 + 1;
                        dx1 = ptInPlane.X - (float)x1;
                        if (dx1 < 0) dx1 = 0;
                        dx1 = 1f - dx1;
                        dx2 = 1f - dx1;
                        dy1 = ptInPlane.Y - (float)y1;
                        if (dy1 < 0) dy1 = 0;
                        dy1 = 1f - dy1;
                        dy2 = 1f - dy1;
                        dx1y1 = dx1 * dy1;
                        dx1y2 = dx1 * dy2;
                        dx2y1 = dx2 * dy1;
                        dx2y2 = dx2 * dy2;
                        //use 4 points

                        Drawing.Color x1y1Color = srcCB.GetPixel(x1, y1);
                        Drawing.Color x2y1Color = srcCB.GetPixel(x2, y1);
                        Drawing.Color x1y2Color = srcCB.GetPixel(x1, y2);
                        Drawing.Color x2y2Color = srcCB.GetPixel(x2, y2);
                        float a = (x1y1Color.alpha * dx1y1) + (x2y1Color.alpha * dx2y1) + (x1y2Color.alpha * dx1y2) + (x2y2Color.alpha * dx2y2);
                        float b = (x1y1Color.blue * dx1y1) + (x2y1Color.blue * dx2y1) + (x1y2Color.blue * dx1y2) + (x2y2Color.blue * dx2y2);
                        float g = (x1y1Color.green * dx1y1) + (x2y1Color.green * dx2y1) + (x1y2Color.green * dx1y2) + (x2y2Color.green * dx2y2);
                        float r = (x1y1Color.red * dx1y1) + (x2y1Color.red * dx2y1) + (x1y2Color.red * dx1y2) + (x2y2Color.red * dx2y2);
                        destWriter.SetPixel(x, y, new Drawing.Color((byte)a, (byte)b, (byte)g, (byte)r));
                        //destCB.SetColorPixel(x, y, new ColorRGBA((byte)b, (byte)g, (byte)r, (byte)a));
                    }
                }
            }
            return destCB;
        }
        ActualImage GetTransformedBicubicInterpolation()
        {
            //4 points sampling
            //weight between four point


            PointF ptInPlane = new PointF();
            int x1, x2, y1, y2;
            double dab, dbc, dcd, dda;
            float dx1, dx2, dy1, dy2, dx1y1, dx1y2, dx2y1, dx2y2;
            int rectWidth = rect.Width;
            int rectHeight = rect.Height;
            var ab_vec = this.AB;
            var bc_vec = this.BC;
            var cd_vec = this.CD;
            var da_vec = this.DA;
            byte[] buffer = srcCB.GetBuffer();
            int stride = srcCB.Stride;
            int bmpWidth = srcCB.Width;
            int bmpHeight = srcCB.Height;
            BufferReader4 reader = new BufferReader4(buffer, stride, bmpWidth, bmpHeight);
            MyColor[] pixelBuffer = new MyColor[16];
            byte[] sqPixs = new byte[16];
            //Bitmap outputbmp = new Bitmap(rectWidth, rectHeight, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
            ////-----------------------------------------------
            //var bmpdata2 = outputbmp.LockBits(new Rectangle(0, 0, rectWidth, rectHeight),
            //    System.Drawing.Imaging.ImageLockMode.ReadWrite, outputbmp.PixelFormat);
            ////-----------------------------------------

            ActualImage destCB = new ActualImage(rect.Width, rect.Height, PixelFormat.ARGB32);
            MyImageReaderWriter destWriter = new MyImageReaderWriter();
            destWriter.ReloadImage(destCB);
            //PointF ptInPlane = new PointF();

            //int stride2 = bmpdata2.Stride;
            //byte[] outputBuffer = new byte[stride2 * outputbmp.Height];

            // int targetPixelIndex = 0;
            // int startLine = 0;

            int rectLeft = this.rect.Left;
            int rectTop = this.rect.Top;
            for (int y = 0; y < rectHeight; ++y)
            {
                for (int x = 0; x < rectWidth; ++x)
                {
                    PointF srcPt = new PointF(x, y);
                    srcPt.Offset(rectLeft, rectTop);
                    if (!IsOnPlaneABCD(srcPt))
                    {
                        continue;
                    }
                    //-------------------------------------
                    dab = Math.Abs(new Vector(vertex[0], srcPt).CrossProduct(ab_vec));
                    dbc = Math.Abs(new Vector(vertex[1], srcPt).CrossProduct(bc_vec));
                    dcd = Math.Abs(new Vector(vertex[2], srcPt).CrossProduct(cd_vec));
                    dda = Math.Abs(new Vector(vertex[3], srcPt).CrossProduct(da_vec));
                    ptInPlane.X = (float)(srcW * (dda / (dda + dbc)));
                    ptInPlane.Y = (float)(srcH * (dab / (dab + dcd)));
                    x1 = (int)ptInPlane.X;
                    y1 = (int)ptInPlane.Y;
                    if (x1 >= 2 && x1 < srcW - 2 && y1 >= 2 && y1 < srcH - 2)
                    {
                        reader.SetStartPixel(x1, y1);
                        reader.Read16(pixelBuffer);
                        //do interpolate

                        //find src pixel and approximate  
                        MyColor color = GetApproximateColor_Bicubic(reader,
                           ptInPlane.X,
                           ptInPlane.Y);
                        //outputBuffer[targetPixelIndex] = (byte)color.b;
                        //outputBuffer[targetPixelIndex + 1] = (byte)color.g;
                        //outputBuffer[targetPixelIndex + 2] = (byte)color.r;
                        //outputBuffer[targetPixelIndex + 3] = (byte)color.a;
                        //targetPixelIndex += 4;

                        destWriter.SetPixel(x, y, new Drawing.Color(color.a, color.b, color.g, color.r)); //TODO:review here blue switch to red channel
                    }
                }
                //newline
                // startLine += stride2;
                //targetPixelIndex = startLine;
            }
            //------------------------
            //System.Runtime.InteropServices.Marshal.Copy(
            //outputBuffer, 0,
            //bmpdata2.Scan0, outputBuffer.Length);
            //outputbmp.UnlockBits(bmpdata2);
            ////outputbmp.Save("d:\\WImageTest\\n_lion_bicubic.png");
            //return outputbmp;
            return destCB;
        }
 ActualImage GetTransformedBitmapNoInterpolation()
 {
     var destCB = new ActualImage(rect.Width, rect.Height, PixelFormat.ARGB32);
     var destWriter = new MyImageReaderWriter();
     destWriter.ReloadImage(destCB);
     PointF ptInPlane = new PointF();
     int x1, x2, y1, y2;
     double dab, dbc, dcd, dda;
     float dx1, dx2, dy1, dy2, dx1y1, dx1y2, dx2y1, dx2y2;
     int rectWidth = rect.Width;
     int rectHeight = rect.Height;
     var ab_vec = this.AB;
     var bc_vec = this.BC;
     var cd_vec = this.CD;
     var da_vec = this.DA;
     int rectLeft = this.rect.Left;
     int rectTop = this.rect.Top;
     for (int y = 0; y < rectHeight; ++y)
     {
         for (int x = 0; x < rectWidth; ++x)
         {
             PointF srcPt = new PointF(x, y);
             srcPt.Offset(rectLeft, rectTop);
             if (!IsOnPlaneABCD(srcPt))
             {
                 continue;
             }
             x1 = (int)ptInPlane.X;
             y1 = (int)ptInPlane.Y;
             destWriter.SetPixel(x, y, srcCB.GetPixel(x1, y1));
             //-------------------------------------
             dab = Math.Abs((new Vector(vertex[0], srcPt)).CrossProduct(ab_vec));
             dbc = Math.Abs((new Vector(vertex[1], srcPt)).CrossProduct(bc_vec));
             dcd = Math.Abs((new Vector(vertex[2], srcPt)).CrossProduct(cd_vec));
             dda = Math.Abs((new Vector(vertex[3], srcPt)).CrossProduct(da_vec));
             ptInPlane.X = (float)(srcW * (dda / (dda + dbc)));
             ptInPlane.Y = (float)(srcH * (dab / (dab + dcd)));
         }
     }
     return destCB;
 }
        private bool IsOnPlaneABCD(PointF pt) //  including point on border
        {
            if (!Vector.IsCCW(pt, vertex[0], vertex[1]))
            {
                if (!Vector.IsCCW(pt, vertex[1], vertex[2]))
                {
                    if (!Vector.IsCCW(pt, vertex[2], vertex[3]))
                    {
                        if (Vector.IsCCW(pt, vertex[3], vertex[0]))
                            return true;
                    }
                }
            }

            return false;
        }
 public static double DistancePointLine(PointF pt, PointF lnA, PointF lnB)
 {
     Vector v1 = new Vector(lnA, lnB);
     Vector v2 = new Vector(lnA, pt);
     v1 /= v1.Magnitude;
     return Math.Abs(v2.CrossProduct(v1));
 }
 public static bool IsCCW(PointF pt1, PointF pt2, PointF pt3)
 {
     Vector V21 = new Vector(pt2, pt1);
     Vector v23 = new Vector(pt2, pt3);
     return V21.CrossProduct(v23) > 0;  // sin(angle pt2 pt1 pt3) < 0, 180<angle pt2 pt1 pt3 <360
 }
 public static bool IsClockwise(PointF pt1, PointF pt2, PointF pt3)
 {
     Vector V21 = new Vector(pt2, pt1);
     Vector v23 = new Vector(pt2, pt3);
     return V21.CrossProduct(v23) < 0; // sin(angle pt1 pt2 pt3) > 0, 0<angle pt1 pt2 pt3 <180
 }