aaform.hpp
上传用户:oersted3
上传日期:2022-05-07
资源大小:281k
文件大小:26k
源码类别:

图形图像处理

开发平台:

Visual C++

  1. #ifndef AAROT_HPP
  2. #define AAROT_HPP
  3. #include <windows.h>
  4. #include <iostream>
  5. #include <vector>
  6. #include <math.h>
  7. #define aaf_abs(a) (((a) < 0)?(-(a)):(a))
  8. typedef bool(* aaf_callback) (double);
  9. struct aaf_pnt
  10. {
  11. double x,y;
  12. inline aaf_pnt(){}
  13.     inline aaf_pnt(double x,double y):x(x),y(y){}
  14. };
  15. struct aaf_dblrgbquad
  16. {
  17. double red, green, blue, alpha;
  18. };
  19. struct aaf_indll
  20. {
  21.     aaf_indll * next;
  22.     int ind;
  23. };
  24. class aaform
  25. {
  26. public:
  27.     static bool transform(HBITMAP, HBITMAP, std::vector<double>, std::vector<double>, aaf_callback);
  28.     static HBITMAP createtransform(HBITMAP, std::vector<double>, std::vector<double>, aaf_callback, int);
  29.     //uses of transform
  30.     static HBITMAP rotate(HBITMAP, double, aaf_callback, int);
  31.     static HBITMAP stretch(HBITMAP, double, double, aaf_callback, int);
  32.     static HBITMAP skewhorizontal(HBITMAP, double, aaf_callback, int);
  33.     static HBITMAP skewverticle(HBITMAP, double, aaf_callback, int);
  34. private:
  35.     //used in dotransform
  36.     static aaf_pnt * pixelgrid;
  37.     static int outstartx;
  38.     static int outstarty;
  39.     static int outwidth;
  40.     static int outheight;
  41.     //used in pix_overlap
  42.     static aaf_pnt * polyoverlap;
  43.     static int polyoverlapsize;
  44.     static aaf_pnt * polysorted;
  45.     static int polysortedsize;
  46.     static aaf_pnt * corners;
  47.     //misc.
  48.     static int ja [];
  49.     static inline int roundup(double a) {if (aaf_abs(a - round(a)) < 1e-9) return round(a); else if ((int) a > a) return (int)a; else return (int)a + 1;}
  50.     static inline int rounddown(double a) {if (aaf_abs(a - round(a)) < 1e-9) return round(a); else if ((int) a < a) return (int)a; else return (int)a - 1;}
  51.     static inline int round(double a) {return (int)(a + 0.5);}
  52.     static inline BYTE byterange(double a) {int b = round(a); if (b <= 0) return 0; else if (b >= 255) return 255; else return (BYTE)b;}
  53.     static inline double aaf_min(double & a, double & b) {if (a < b) return a; else return b;}
  54.     static inline double aaf_max(double & a, double & b) {if (a > b) return a; else return b;}
  55.     static inline double aaf_cos(double);
  56.     static inline double aaf_sin(double);
  57.     static inline double area();
  58.     static inline void sortpoints();
  59.     static inline bool ptinconvexpolygon(aaf_pnt *, aaf_pnt);
  60.     static inline double pixoverlap(aaf_pnt *);
  61.     static bool creategrid(BITMAP &, std::vector<double> &, std::vector<double> &);
  62.     static bool dotransform(HBITMAP, HBITMAP, aaf_callback);
  63. };
  64. aaf_pnt * aaform::pixelgrid;
  65. int aaform::outstartx;
  66. int aaform::outstarty;
  67. int aaform::outwidth;
  68. int aaform::outheight;
  69. aaf_pnt * aaform::polyoverlap;
  70. int aaform::polyoverlapsize;
  71. aaf_pnt * aaform::polysorted;
  72. int aaform::polysortedsize;
  73. aaf_pnt * aaform::corners;
  74. int aaform::ja [] = {1, 2, 3, 0};
  75. //Prevent Float Errors with Cos and Sin
  76. double aaform::aaf_cos(double degrees)
  77. {
  78.     double ret;
  79.     double off = (degrees / 30 - round(degrees / 30));
  80.     if (off < .0000001 && off > -.0000001)
  81.     {
  82.         int idegrees = (int)round(degrees);
  83.         idegrees = (idegrees < 0) ? (360 - (-idegrees % 360))  : (idegrees % 360);
  84.         switch (idegrees)
  85.         {
  86.             case 0: ret=1.0; break;
  87.             case 30: ret=0.866025403784439; break;
  88.             case 60: ret=0.5; break;
  89.             case 90: ret=0.0; break;
  90.             case 120: ret=-0.5; break;
  91.             case 150: ret=-0.866025403784439; break;
  92.             case 180: ret=-1.0; break;
  93.             case 210: ret=-0.866025403784439; break;
  94.             case 240: ret=-0.5; break;
  95.             case 270: ret=0.0; break;
  96.             case 300: ret=0.5; break;
  97.             case 330: ret=0.866025403784439; break;
  98.             case 360: ret=1.0; break;
  99.             default: ret=cos(degrees * 3.14159265358979 / 180);  // it shouldn't get here
  100.         }
  101.         return ret;
  102.     }
  103.     else
  104.         return cos(degrees * 3.14159265358979 / 180);
  105. }
  106. double aaform::aaf_sin(double degrees)
  107. {
  108.     //sin(x) = cos(x + PI / 2)
  109.     return aaf_cos(degrees + 90.0);
  110. }
  111. //Note that this function is specific to Aaform to save time
  112. double aaform::area()
  113. {
  114.     double ret = 0.0;
  115.     //Loop through each triangle with respect to (0, 0) and add the cross multiplication
  116.     for (int i = 0; i + 1 < polysortedsize; i++)
  117.         ret += polysorted[i].x * polysorted[i + 1].y - polysorted[i + 1].x * polysorted[i].y;
  118.     //Take the absolute value over 2
  119.     return aaf_abs(ret) / 2.0;
  120. }
  121. void aaform::sortpoints()
  122. {
  123.     //Why even bother?
  124.     if (polyoverlapsize < 3)
  125.         return;
  126.     //polyoverlap is a triangle, points cannot be out of order
  127.     if (polyoverlapsize == 3)
  128.     {
  129.         polysortedsize = polyoverlapsize - 1;
  130.         polysorted[0].x = polyoverlap[1].x - polyoverlap[0].x;
  131.         polysorted[0].y = polyoverlap[1].y - polyoverlap[0].y;
  132.         polysorted[1].x = polyoverlap[2].x - polyoverlap[0].x;
  133.         polysorted[1].y = polyoverlap[2].y - polyoverlap[0].y;
  134.         return;
  135.     }
  136.     
  137.     aaf_indll * root = new aaf_indll;
  138.     root->next = NULL;
  139.     //begin sorting the points.  Note that the first element is left out and all other elements are offset by it's values
  140.     for (int i = 1; i < polyoverlapsize; i++)
  141.     {
  142.         polyoverlap[i].x = polyoverlap[i].x - polyoverlap[0].x;
  143.         polyoverlap[i].y = polyoverlap[i].y - polyoverlap[0].y;
  144.         aaf_indll * node = root;
  145.         //Loop until the point polyoverlap[i] is can be sorted (counter) clockwiswe (I'm not sure which way it's sorted)
  146.         while (true)
  147.         {
  148.             if (node->next)
  149.             {
  150.                 if (polyoverlap[i].x * polyoverlap[node->next->ind].y - polyoverlap[node->next->ind].x * polyoverlap[i].y < 0)
  151.                 {
  152.                     //Insert point before this element
  153.                     aaf_indll * temp = node->next;
  154.                     node->next = new aaf_indll;
  155.                     node->next->ind = i;
  156.                     node->next->next = temp;
  157.                     break;
  158.                 }
  159.             }
  160.             else
  161.             {
  162.                 //Add point to the end of list
  163.                 node->next = new aaf_indll;
  164.                 node->next->ind = i;
  165.                 node->next->next = NULL;
  166.                 break;
  167.             }
  168.             node = node->next;
  169.         }
  170.     }
  171.     //We can leave out the first point because it's offset position is going to be (0, 0)
  172.     polysortedsize = 0;
  173.     aaf_indll * node = root;
  174.     aaf_indll * temp;
  175.     //Add the sorted points to polysorted and clean up memory
  176.     while (node)
  177.     {
  178.         temp = node;
  179.         node = node->next;
  180.         if (node)
  181.             polysorted[polysortedsize++] = polyoverlap[node->ind];
  182.         delete temp;
  183.     }
  184. }
  185. //This funciton works for any convex polygon
  186. bool aaform::ptinconvexpolygon(aaf_pnt * p, aaf_pnt pt)
  187. {
  188.     int dir = 0;
  189.     int j;
  190.     //Basically what we are doing is seeing if pt is on the same side of each face of the polygon through cross multiplication
  191.     for (int i = 0; i < 4; i++)
  192.     {
  193.         j = ja[i];
  194.         double cross = (p[i].x - pt.x) * (p[j].y - pt.y) - (p[j].x - pt.x) * (p[i].y - pt.y);
  195.         if (cross == 0)
  196.             continue;
  197.         if (cross > 0)
  198.         {
  199.             if (dir == -1)
  200.                 return false;
  201.             dir = 1;
  202.         }
  203.         else
  204.         {
  205.             if (dir == 1)
  206.                 return false;
  207.             dir = -1;
  208.         }
  209.     }
  210.     return true;
  211. }
  212. //Finds the area of overlap accross p and the square (0,0)-(1,1)
  213. double aaform::pixoverlap(aaf_pnt * p)
  214. {
  215.     polyoverlapsize = 0;
  216.     polysortedsize = 0;
  217.     double minx, maxx, miny, maxy;
  218.     int j;
  219.     double z;
  220.     for (int i = 0; i < 4; i++)
  221.     {        
  222.         //Search for source points within the destination quadrolateral
  223.         if (p[i].x >= 0 && p[i].x <= 1 && p[i].y >= 0 && p[i].y <= 1)
  224.             polyoverlap[polyoverlapsize++] = p[i];
  225.         //Search for destination points within the source quadrolateral
  226.         if (ptinconvexpolygon(p, corners[i]))
  227.             polyoverlap[polyoverlapsize++] = corners[i];
  228.         //Search for line intersections
  229.         j = ja[i];
  230.         minx = aaf_min(p[i].x, p[j].x);
  231.         miny = aaf_min(p[i].y, p[j].y);
  232.         maxx = aaf_max(p[i].x, p[j].x);
  233.         maxy = aaf_max(p[i].y, p[j].y);
  234.         if (minx < 0.0 && 0.0 < maxx)
  235.         {//Cross left
  236.             z = p[i].y - p[i].x * (p[i].y - p[j].y) / (p[i].x - p[j].x);
  237.             if (z >= 0.0 && z <= 1.0)
  238.             {
  239.                 polyoverlap[polyoverlapsize].x = 0.0;
  240.                 polyoverlap[polyoverlapsize++].y = z;
  241.             }
  242.         }
  243.         if (minx < 1.0 && 1.0 < maxx)
  244.         {//Cross right
  245.             z = p[i].y + (1 - p[i].x) * (p[i].y - p[j].y) / (p[i].x - p[j].x);
  246.             if (z >= 0.0 && z <= 1.0)
  247.             {
  248.                 polyoverlap[polyoverlapsize].x = 1.0;
  249.                 polyoverlap[polyoverlapsize++].y = z;
  250.             }
  251.         }
  252.         if (miny < 0.0 && 0.0 < maxy)
  253.         {//Cross bottom
  254.             z = p[i].x - p[i].y * (p[i].x - p[j].x) / (p[i].y - p[j].y);
  255.             if (z >= 0.0 && z <= 1.0)
  256.             {
  257.                 polyoverlap[polyoverlapsize].x = z;
  258.                 polyoverlap[polyoverlapsize++].y = 0.0;
  259.             }
  260.         }
  261.         if (miny < 1.0 && 1.0 < maxy)
  262.         {//Cross top
  263.             z = p[i].x + (1 - p[i].y) * (p[i].x - p[j].x) / (p[i].y - p[j].y);
  264.             if (z >= 0.0 && z <= 1.0)
  265.             {
  266.                 polyoverlap[polyoverlapsize].x = z;
  267.                 polyoverlap[polyoverlapsize++].y = 1.0;
  268.             }
  269.         }
  270.     }        
  271.     //Sort the points and return the area
  272.     sortpoints();
  273.     return area();
  274. }
  275. bool aaform::dotransform(HBITMAP src, HBITMAP dst, aaf_callback callbackfunc)
  276. {
  277.     //Get source bitmap's information
  278.     BITMAP srcbmp;
  279.     if (GetObject(src, sizeof(srcbmp), &srcbmp) == 0)
  280. return false;
  281.     //Get the destination bitmap's information
  282.     BITMAP dstbmp;
  283.     if (GetObject(dst, sizeof(dstbmp), &dstbmp) == 0)
  284. return false;
  285.     //Create the source dib array and the dstdib array
  286.     RGBQUAD * srcdib = new RGBQUAD[srcbmp.bmWidth * srcbmp.bmHeight];
  287.     aaf_dblrgbquad * dbldstdib = new aaf_dblrgbquad[outwidth * outheight];
  288. memset(dbldstdib, 0, outwidth * outheight * sizeof(aaf_dblrgbquad));
  289.     //Load source bits into srcdib
  290.     BITMAPINFO srcdibbmap;
  291.     srcdibbmap.bmiHeader.biSize = sizeof(srcdibbmap.bmiHeader);
  292.     srcdibbmap.bmiHeader.biWidth = srcbmp.bmWidth;
  293.     srcdibbmap.bmiHeader.biHeight = -srcbmp.bmHeight;
  294.     srcdibbmap.bmiHeader.biPlanes = 1;
  295.     srcdibbmap.bmiHeader.biBitCount = 32;
  296.     srcdibbmap.bmiHeader.biCompression = BI_RGB;
  297.     //Get the source bits
  298.     HDC ldc = CreateCompatibleDC(0);
  299.     GetDIBits(ldc, src, 0, srcbmp.bmHeight, srcdib, &srcdibbmap, DIB_RGB_COLORS);
  300.     DeleteDC(ldc);
  301.     //Create polygon arrays
  302.     aaf_pnt * p = new aaf_pnt[4];
  303.     aaf_pnt * poffset = new aaf_pnt[4];
  304. int x, y;
  305.     //Loop through the source's pixels
  306.     for ( x = 0; x < srcbmp.bmWidth; x++)
  307.     {
  308.         for ( y = 0; y < srcbmp.bmHeight; y++)
  309.         {
  310.             //Construct the source pixel's rotated polygon from pixelgrid
  311.             p[0] = pixelgrid[x + y * (srcbmp.bmWidth + 1)];
  312.             p[1] = pixelgrid[(x + 1) + y * (srcbmp.bmWidth + 1)];
  313.             p[2] = pixelgrid[(x + 1) + (y + 1) * (srcbmp.bmWidth + 1)];
  314.             p[3] = pixelgrid[x + (y + 1) * (srcbmp.bmWidth + 1)];
  315.             //Find the scan area on the destination's pixels
  316.             int mindx = 0x7FFFFFFF;
  317.             int mindy = 0x7FFFFFFF;
  318.             int maxdx = 0x80000000;
  319.             int maxdy = 0x80000000;
  320.             for (int i = 0; i < 4; i++)
  321.             {
  322. if (rounddown(p[i].x) < mindx) mindx = rounddown(p[i].x);
  323.                 if (roundup(p[i].x) > maxdx) maxdx = roundup(p[i].x);
  324. if (rounddown(p[i].y) < mindy) mindy = rounddown(p[i].y);
  325. if (roundup(p[i].y) > maxdy) maxdy = roundup(p[i].y);
  326.             }
  327.             
  328.             int SrcIndex = x + y * srcbmp.bmWidth;
  329.             //loop through the scan area to find where source(x, y) overlaps with the destination pixels
  330.             for (int xx = mindx - 1; xx <= maxdx; xx++)
  331.             {
  332.                 if (xx < 0 || xx >= dstbmp.bmWidth)
  333.                     continue;
  334.                 for (int yy = mindy - 1; yy <= maxdy; yy++)
  335.                 {
  336.                     if(yy < 0 || yy >= dstbmp.bmHeight)
  337.                         continue;
  338.                     //offset p and by (xx,yy) and put that into poffset
  339.                     for (int i = 0; i < 4; i++)
  340.                     {
  341.                         poffset[i].x = p[i].x - xx;
  342.                         poffset[i].y = p[i].y - yy;
  343.                     }
  344.                     
  345.                     //FIND THE OVERLAP *a whole lot of code pays off here*
  346.                     double dbloverlap = pixoverlap(poffset);
  347.                     if (dbloverlap > 0)
  348.                     {
  349.                         int dstindex = xx + yy * outwidth;
  350.                         //Add the rgb and alpha values in proportion to the overlap area
  351.                         dbldstdib[dstindex].red += (double)(srcdib[SrcIndex].rgbRed) * dbloverlap;
  352.                         dbldstdib[dstindex].blue += (double)(srcdib[SrcIndex].rgbBlue) * dbloverlap;
  353.                         dbldstdib[dstindex].green += (double)(srcdib[SrcIndex].rgbGreen) * dbloverlap;
  354.                         dbldstdib[dstindex].alpha += dbloverlap;
  355.                     }
  356.                 }
  357.             }
  358.         }
  359.         if (callbackfunc != NULL)
  360.         {
  361.             //Send the callback message
  362.             double percentdone = (double)(x + 1) / (double)(srcbmp.bmWidth);
  363.             if (callbackfunc(percentdone))
  364.             {
  365.                 delete [] srcdib;
  366.                 delete [] dbldstdib;
  367.                 delete [] p;
  368.                 delete [] poffset;
  369.                 return false;
  370.             }
  371.         }
  372.     }
  373.     
  374.     //Free memory no longer needed
  375.     delete [] p;
  376.     delete [] poffset;
  377.     delete [] srcdib;
  378.     srcdib = NULL;
  379.     //Create final destination bits
  380.     RGBQUAD * dstdib = new RGBQUAD[dstbmp.bmWidth * dstbmp.bmHeight];
  381.     BITMAPINFO dstdibmap;
  382.     dstdibmap.bmiHeader.biSize = sizeof(dstdibmap.bmiHeader);
  383.     dstdibmap.bmiHeader.biWidth = dstbmp.bmWidth;
  384.     dstdibmap.bmiHeader.biHeight = -dstbmp.bmHeight;
  385.     dstdibmap.bmiHeader.biPlanes = 1;
  386.     dstdibmap.bmiHeader.biBitCount = 32;
  387.     dstdibmap.bmiHeader.biCompression = BI_RGB;
  388.     
  389.     //Load the destination bitmap's bits
  390.     ldc = CreateCompatibleDC(0);
  391.     GetDIBits(ldc, dst, 0, dstbmp.bmHeight, dstdib, &dstdibmap, DIB_RGB_COLORS);
  392.     DeleteDC(ldc);
  393.     //Write to dstdib with the information stored in dbldstdib
  394.     for ( x = 0; x < outwidth; x++)
  395.     {
  396.         if (x + outstartx >= dstbmp.bmWidth)
  397.             continue;
  398.         for ( y = 0; y < outheight; y++)
  399.         {
  400.             if (y + outstarty >= dstbmp.bmHeight)
  401.                 continue;
  402.             int offindex = x + y * outwidth;
  403.             int dstindex = x + outstartx + (y + outstarty) * dstbmp.bmWidth;
  404.             if (dbldstdib[offindex].alpha > 1)
  405.             {//handles wrap around for non-convex transformations
  406.                 dstdib[dstindex].rgbReserved = 0;
  407.                 dstdib[dstindex].rgbRed = byterange(dbldstdib[offindex].red / dbldstdib[offindex].alpha);
  408.                 dstdib[dstindex].rgbGreen = byterange(dbldstdib[offindex].green / dbldstdib[offindex].alpha);
  409.                 dstdib[dstindex].rgbBlue = byterange(dbldstdib[offindex].blue / dbldstdib[offindex].alpha);
  410.             }
  411.             else
  412.             {
  413.                 dstdib[dstindex].rgbReserved = 0;
  414.                 dstdib[dstindex].rgbRed = byterange(dbldstdib[offindex].red + (1 - dbldstdib[offindex].alpha) * (double)dstdib[dstindex].rgbRed);
  415.                 dstdib[dstindex].rgbGreen = byterange(dbldstdib[offindex].green + (1 - dbldstdib[offindex].alpha) * (double)dstdib[dstindex].rgbGreen);
  416.                 dstdib[dstindex].rgbBlue = byterange(dbldstdib[offindex].blue + (1 - dbldstdib[offindex].alpha) * (double)dstdib[dstindex].rgbBlue);
  417.             }
  418.         }
  419.     }
  420.     //Clear memory
  421.     delete [] dbldstdib;
  422.     dbldstdib = NULL;
  423.     //Write the bits into the bitmap and return it
  424.     SetDIBits(0, dst, 0, dstbmp.bmHeight, dstdib, &dstdibmap, DIB_RGB_COLORS);
  425.     
  426.     //Clear memory
  427.     delete [] dstdib;
  428.     dstdib = NULL;
  429.     //:D
  430.     return true;
  431. }
  432. bool aaform::transform(HBITMAP src, HBITMAP dst, std::vector<double> xcorner, std::vector<double> ycorner, aaf_callback callbackfunc)
  433. {
  434.     //Make sure the coordinates are valid
  435.     if (xcorner.size() != 4 || ycorner.size() != 4)
  436.         return false;
  437.     //Load the src bitmaps information
  438.     BITMAP srcbmp;
  439.     if (GetObject(src, sizeof(srcbmp), &srcbmp) == 0)
  440. return false;
  441.     //create the intial arrays
  442.     pixelgrid = new aaf_pnt[(srcbmp.bmWidth + 1) * (srcbmp.bmHeight + 1)];
  443.     polyoverlap = new aaf_pnt[16];
  444.     polysorted = new aaf_pnt[16];
  445.     corners = new aaf_pnt[4];
  446.     
  447. int i;
  448.     //Load the corners array
  449.     double dx[] = {0.0, 1.0, 1.0, 0.0};
  450.     double dy[] = {0.0, 0.0, 1.0, 1.0};
  451.     for ( i = 0; i < 4; i++)
  452.     {
  453.         corners[i].x = dx[i];
  454.         corners[i].y = dy[i];
  455.     }
  456.     //Find the rectangle of dst to draw to
  457.     outstartx = rounddown(xcorner[0]);
  458.     outstarty = rounddown(ycorner[0]);
  459.     outwidth = 0;
  460.     outheight = 0;
  461.     for ( i = 1; i < 4; i++)
  462.     {
  463. if (rounddown(xcorner[i]) < outstartx) outstartx = rounddown(xcorner[i]);
  464.         if (rounddown(ycorner[i]) < outstarty) outstarty = rounddown(ycorner[i]);
  465.     }
  466.     for ( i = 0; i < 4; i++)
  467.     {
  468. if (roundup(xcorner[i] - outstartx) > outwidth) outwidth = roundup(xcorner[i] - outstartx);
  469. if (roundup(ycorner[i] - outstarty) > outheight) outheight = roundup(ycorner[i] - outstarty);
  470.     }
  471.     bool res;
  472.     //fill out pixelgrid array
  473.     res = creategrid(srcbmp, xcorner, ycorner);
  474.     if (res)
  475.     {
  476.         //Do the transformation
  477.         res = dotransform(src, dst, callbackfunc);
  478.     }
  479.     //clear memory
  480.     delete [] corners;
  481.     delete [] polysorted;
  482.     delete [] polyoverlap;
  483.     //Return if the function completed properly
  484.     return res;
  485. }
  486. bool aaform::creategrid(BITMAP & srcbmp, std::vector<double> & xcorner, std::vector<double> & ycorner)
  487. {
  488.     //mmm geometry
  489.     double * sideradius = new double[4];
  490.     double * sidecos = new double[4];
  491.     double * sidesin = new double[4];
  492.     //First we find the radius, cos, and sin of each side of the polygon created by xcorner and ycorner
  493.     int j;
  494.     for (int i = 0; i < 4; i++)
  495.     {
  496.         j = ja[i];
  497.         sideradius[i] = sqrt((xcorner[i] - xcorner[j]) * (xcorner[i] - xcorner[j]) + (ycorner[i] - ycorner[j]) * (ycorner[i] - ycorner[j]));
  498.         sidecos[i] = (xcorner[j] - xcorner[i]) / sideradius[i];
  499.         sidesin[i] = (ycorner[j] - ycorner[i]) / sideradius[i];
  500.     }
  501.     //Next we create two lines in Ax + By = C form
  502.     for (int x = 0; x < srcbmp.bmWidth + 1; x++)
  503.     {
  504.         double topdist = ((double)x / (srcbmp.bmWidth)) * sideradius[0];
  505.         double ptxtop =  xcorner[0] + topdist * sidecos[0];
  506.         double ptytop = ycorner[0] + topdist * sidesin[0];
  507.         double botdist = (1.0 - (double)x / (srcbmp.bmWidth)) * sideradius[2];
  508.         double ptxbot = xcorner[2] + botdist * sidecos[2];
  509.         double ptybot = ycorner[2] + botdist * sidesin[2];
  510.         double Ah = ptybot - ptytop;
  511.         double Bh = ptxtop - ptxbot;
  512.         double Ch = Ah * ptxtop + Bh * ptytop;
  513.         for (int y = 0; y < srcbmp.bmHeight + 1; y++)
  514.         {
  515.             double leftdist = (1.0 - (double)y / (srcbmp.bmHeight)) * sideradius[3];
  516.             double ptxleft =  xcorner[3] + leftdist * sidecos[3];
  517.             double ptyleft = ycorner[3] + leftdist * sidesin[3];
  518.     
  519.             double rightdist = ((double)y / (srcbmp.bmHeight)) * sideradius[1];
  520.             double ptxright = xcorner[1] + rightdist * sidecos[1];
  521.             double ptyright = ycorner[1] + rightdist * sidesin[1];
  522.             double Av = ptyright - ptyleft;
  523.             double Bv = ptxleft - ptxright;
  524.             double Cv = Av * ptxleft + Bv * ptyleft;
  525.     
  526.             //Find where the lines intersect and store that point in the pixelgrid array
  527.             double det = Ah * Bv - Av * Bh;
  528.             if (aaf_abs(det) < 1e-9)
  529.             {
  530.                 delete [] sidesin;
  531.                 delete [] sidecos;
  532.                 delete [] sideradius;
  533.                 return false;
  534.             }
  535.             else
  536.             {
  537.                 int ind = x + y * (srcbmp.bmWidth + 1);
  538.                 pixelgrid[ind].x = (Bv * Ch - Bh * Cv) / det;
  539.                 pixelgrid[ind].y = (Ah * Cv - Av * Ch) / det;
  540.             }
  541.         }
  542.     }
  543.     delete [] sidesin;
  544.     delete [] sidecos;
  545.     delete [] sideradius;
  546.     //Yayy we didn't fail
  547.     return true;
  548. }
  549. //automatically offsets the corners of the image, creates a bitmap of the required size to fit the image, calls transform, and returns the bitmap it created
  550. HBITMAP aaform::createtransform(HBITMAP src, std::vector<double> xcorner, std::vector<double> ycorner, aaf_callback callbackfunc, int bgcolor)
  551. {
  552.     //Check if it's a valid array
  553.     if (xcorner.size() != 4 || ycorner.size() != 4)
  554.         return NULL;
  555.     //Find the dimensions of the bitmap that needs to be created and offset the corners so that the lowest x value is at 0 and the lowest y is at 0
  556.     RECT rc;
  557.     rc.left = 0;
  558.     rc.right = 0;
  559.     rc.top = 0;
  560.     rc.bottom = 0;
  561. int i;
  562.     double offx = xcorner[0];
  563.     double offy = ycorner[0];
  564.     for ( i = 1; i < 4; i++)
  565.     {
  566. if (xcorner[i] < offx) offx = xcorner[i];
  567. if (ycorner[i] < offy) offy = ycorner[i];
  568.     }
  569.     for ( i = 0; i < 4; i++)
  570.     {
  571.         xcorner[i] -= offx;
  572.         ycorner[i] -= offy;
  573. if (roundup(xcorner[i]) > rc.right) rc.right = roundup(xcorner[i]);
  574.         if (roundup(ycorner[i]) > rc.bottom) rc.bottom = roundup(ycorner[i]);
  575.     }
  576.     //Create a temp dc
  577.     HDC ldc = CreateCompatibleDC(0);
  578.     //Create the destination bitmap
  579.     DEVMODE dvmd;
  580.     dvmd.dmSize = sizeof(dvmd);
  581.     EnumDisplaySettings(0, ENUM_CURRENT_SETTINGS, &dvmd);
  582.     HBITMAP hBmp = CreateBitmap(rc.right, rc.bottom, 1, dvmd.dmBitsPerPel, NULL);
  583.     //Select the bitmap into ldc
  584.     SelectObject(ldc, hBmp);
  585.     //Create a solid brush of color defined by bgcolor
  586.     HBRUSH hBrsh = CreateSolidBrush((COLORREF)bgcolor);
  587.     //Fill the background with this color
  588.     FillRect(ldc, &rc, hBrsh);
  589.     //Delete the brush
  590.     DeleteObject(hBrsh);
  591.     //Delete ldc
  592.     DeleteDC(ldc);
  593.     //do the transformation
  594.     transform(src, hBmp, xcorner, ycorner, callbackfunc);
  595.     //mmm
  596.     return hBmp;
  597. }
  598. //This works just as well as Aarot (might be a little slower due to no specialization for rotations in transform)
  599. HBITMAP aaform::rotate(HBITMAP src, double degrees, aaf_callback callbackfunc, int bgcolor)
  600. {
  601.     //Load the source bitmap's info
  602.     BITMAP srcbmp;
  603.     if (GetObject(src, sizeof(srcbmp), &srcbmp) == 0)
  604. return false;
  605.     std::vector<double> x, y;
  606.     //Get half the width and half the height of the image
  607.     double hwidth = (double)srcbmp.bmWidth / 2.0;
  608.     double hheight = (double)srcbmp.bmHeight / 2.0;
  609.     double coss = aaf_cos(degrees);
  610.     double sins = aaf_sin(degrees);
  611.     //Find the rotated coordinates, createtransform will offset them so none of them are negative
  612.     x.push_back(coss * -hwidth - sins * -hheight);
  613.     y.push_back(sins * -hwidth + coss * -hheight);
  614.     x.push_back(coss * hwidth - sins * -hheight);
  615.     y.push_back(sins * hwidth + coss * -hheight);
  616.     x.push_back(coss * hwidth - sins * hheight);
  617.     y.push_back(sins * hwidth + coss * hheight);
  618.     x.push_back(coss * -hwidth - sins * hheight);
  619.     y.push_back(sins * -hwidth + coss * hheight);
  620.     //do the rotation using transform
  621.     return createtransform(src, x, y, callbackfunc, bgcolor);
  622. }
  623. HBITMAP aaform::stretch(HBITMAP src, double xratio, double yratio, aaf_callback callbackfunc, int bgcolor)
  624. {
  625.     //Load the source bitmap's info
  626.     BITMAP srcbmp;
  627.     if (GetObject(src, sizeof(srcbmp), &srcbmp) == 0)
  628. return false;
  629.     std::vector<double> x, y;
  630.     x.push_back(0.0);
  631.     y.push_back(0.0);
  632.     x.push_back(xratio * srcbmp.bmWidth);
  633.     y.push_back(0.0);
  634.     x.push_back(xratio * srcbmp.bmWidth);
  635.     y.push_back(yratio * srcbmp.bmHeight);
  636.     x.push_back(0.0);
  637.     y.push_back(yratio * srcbmp.bmHeight);
  638.     //do the stretch using transform
  639.     return createtransform(src, x, y, callbackfunc, bgcolor);
  640. }
  641. HBITMAP aaform::skewhorizontal(HBITMAP src, double angle, aaf_callback callbackfunc, int bgcolor)
  642. {
  643.     //Load the source bitmap's info
  644.     BITMAP srcbmp;
  645.     if (GetObject(src, sizeof(srcbmp), &srcbmp) == 0)
  646. return false;
  647.     std::vector<double> x, y;
  648.     double tans = tan(angle / 180.0 * 3.141592653589793);
  649.     x.push_back(tans * srcbmp.bmHeight);
  650.     y.push_back(0.0);
  651.     x.push_back(tans * srcbmp.bmHeight + srcbmp.bmWidth);
  652.     y.push_back(0.0);
  653.     x.push_back(srcbmp.bmWidth);
  654.     y.push_back(srcbmp.bmHeight);
  655.     x.push_back(0.0);
  656.     y.push_back(srcbmp.bmHeight);
  657.     //do the skew using transform
  658.     return createtransform(src, x, y, callbackfunc, bgcolor);
  659. }
  660. HBITMAP aaform::skewverticle(HBITMAP src, double angle, aaf_callback callbackfunc, int bgcolor)
  661. {
  662.     //Load the source bitmap's info
  663.     BITMAP srcbmp;
  664.     if (GetObject(src, sizeof(srcbmp), &srcbmp) == 0)
  665. return false;
  666.     std::vector<double> x, y;
  667.     double tans = tan(angle / 180.0 * 3.141592653589793);
  668.     x.push_back(0.0);
  669.     y.push_back(tans * srcbmp.bmWidth);
  670.     x.push_back(srcbmp.bmWidth);
  671.     y.push_back(0.0);
  672.     x.push_back(srcbmp.bmWidth);
  673.     y.push_back(srcbmp.bmHeight);
  674.     x.push_back(0.0);
  675.     y.push_back(tans * srcbmp.bmWidth + srcbmp.bmHeight);
  676.     //do the skew using transform
  677.     return createtransform(src, x, y, callbackfunc, bgcolor);
  678. }
  679. #endif