Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush Python API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Recent
    • Tags
    • Users
    • Login

    Transform arbitrary quadrangle to square

    Scheduled Pinned Locked Moved SDK Help
    4 Posts 0 Posters 394 Views
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • H Offline
      Helper
      last edited by

      THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

      On 29/06/2009 at 18:27, xxxxxxxx wrote:

      User Information:
      Cinema 4D Version:   R10-R11 
      Platform:   Windows  ;   Mac OSX  ; 
      Language(s) :     C++  ;

      ---------
      I'm having a brainfart and difficulty finding the correct affine transformation to map an arbitrary (but planar) quadrangle into a square space. Something similar is done in UV mapping but, again, having difficulty finding information on this. I'll keep looking but does anybody know how to do this?

      Thanks!

      1 Reply Last reply Reply Quote 0
      • H Offline
        Helper
        last edited by

        THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

        On 29/06/2009 at 23:45, xxxxxxxx wrote:

        I wrote once a little COFFEE plugin based on an algorithm posted by Per Anders that does exactly the same thing. It turns selected polygons into squares.

        > \> MyMenuPlugin::Execute(doc) \> { \> // Called when the menu item is chosen \>      var op = GetActiveObject(doc); \>      if(!op) return; \>      if (!instanceof(op,PolygonObject)) return; \>         var sel=op->GetPolygonSelection(); \>         if (!sel) return; // no polygon selection, exit now \>          \>         doc->StartUndo(); \>      doc->AddUndo(UNDO_OBJECT,op); \> \>     \>         var cnt=op->GetPolygonCount(); \>         var pnt=op->GetPoints(); \>     \>         //loop through all the polygons to find the selected ones \>         var i=0; \>         for (i=0;i<cnt;i++) \>         { \>           //check if the current polygon is selected \>              if (sel->IsSelected(i)) \>              { \>                //get the polygon points \>                var pol=op->GetPolygon(i); \>                var p1=pnt[pol->a]; \>                var p2=pnt[pol->b]; \>                var p3=pnt[pol->c]; \>                var p4=pnt[pol->d]; \>     \>                   //calculate the polygon normal, midpoint and size \>                     var dir=vnorm(vcross(p3-p1,p4-p2)); \>                var p5=(p1+p2+p3+p4)/4.0; \>                     var len=(vlen(p1-p3)+vlen(p2-p4))/4.0; \>     \>                     //set the point positions correctly \>                     var v1=vnorm(vcross(dir,vnorm(p5-p2))); \>                var v2=vnorm(vcross(dir,v1)); \>                p1=(len\*v1)+p5; \>                p2=(len\*v2)+p5; \>                p3=(-len\*v1)+p5; \>                p4=(-len\*v2)+p5; \>     \>                pnt[pol->a]=p1; \>                pnt[pol->b]=p2; \>                pnt[pol->c]=p3; \>                pnt[pol->d]=p4; \>     \>                op->SetPoints(pnt); \>                op->Message(MSG_UPDATE); \>              } \>         } \> // TODO: Do whatever you want \>      doc->EndUndo(); \>      op->Message(MSG_UPDATE); \>      GeEventAdd(DOCUMENT_CHANGED); \> } \>

        cheers,
        Matthias

        1 Reply Last reply Reply Quote 0
        • H Offline
          Helper
          last edited by

          THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

          On 30/06/2009 at 14:47, xxxxxxxx wrote:

          Unfortunately, it must be a transformation matrix since geometry will be inverse transformed (from the square back to the quadrangle). I've found some quad-to-square algorithms but they aren't working for some reason and there is definitely some modification of the matrix homogeneous vector (something that cannot be done with Cinema 4D's matrix as it is always assumed to be (0,0,0,1)!). Typically, a projective transform is applied (when an affine tranformation cannot).

          1 Reply Last reply Reply Quote 0
          • H Offline
            Helper
            last edited by

            THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

            On 30/06/2009 at 20:50, xxxxxxxx wrote:

            Found it finally! 😄

            Here's the full 'test' plugin code just for the curious. This is a 2D transformation only!

            ////////////////////////////////////////////////////////////////
            // TestingPlugin.cpp
            ////////////////////////////////////////////////////////////////
            // CommandPlugin class
            ////////////////////////////////////////////////////////////////
            // V0.1 2008.05.28 Robert Templeton
            ////////////////////////////////////////////////////////////////

            #include "TestingPlugin.h"

            class Matrix2D
            {
                 public:
                      Real     m0;
                      Real     m1;
                      Real     m3;
                      Real     m4;
                      Real     m5;
                      Real     m7;
                      Real     m12;
                      Real     m13;
                      Real     m15;
                      Matrix2D()
                      {
                           // Unit Matrix
                           m0 =     1.0;
                           m1 =     0.0;
                           m3 =     0.0;
                           m4 =     0.0;
                           m5 =     1.0;
                           m7 =     0.0;
                           m12 =     0.0;
                           m13 =     0.0;
                           m15 =     1.0;
                      }
                      // transform point p by matrix M: q = p*M
                      friend const Vector operator * (const Vector& p, const Matrix2D& M)
                      {
                           Real     d = p.x*M.m3 + p.z*M.m7 + M.m15;
                           if (d)          d = 1.0f/d;
                           else          return Vector(0.0f);
                           Vector     q;
                           q.x =          ((p.x*M.m0 + p.z*M.m4 + M.m12) * d)-0.5f;
                           q.z =          ((p.x*M.m1 + p.z*M.m5 + M.m13) * d)-0.5f;
                           q.y =          0.0f;
                           return q;
                      }
            };

            // Calculate matrix for unit-square to quad mapping
            //                     - vertices        - square->quad transform
            //*---------------------------------------------------------------------------*
            Bool SquareToQuad(Real quad[4][2], Matrix2D* SQ)
            //*---------------------------------------------------------------------------*
            {
                 Real     x0 =     quad[0][0];
                 Real     x1 =     quad[1][0];
                 Real     x2 =     quad[2][0];
                 Real     x3 =     quad[3][0];

            Real     y0 =     quad[0][1];
                 Real     y1 =     quad[1][1];
                 Real     y2 =     quad[2][1];
                 Real     y3 =     quad[3][1];

            Real     dx3 =     x0 - x1 + x2 - x3;
                 Real     dy3 =     y0 - y1 + y2 - y3;

            // afine transform
                 if (!dx3 && !dy3)
                 {
                      SQ->m0 = x1-x0; SQ->m1 = y1-y0; SQ->m3 = 0.0f;
                      SQ->m4 = x2-x1; SQ->m5 = y2-y1; SQ->m7 = 0.0f;
                      SQ->m12 = x0;   SQ->m13 = y0;   SQ->m15 = 1.0f;
                 }
                 // projective transform
                 else
                 {
                      Real dx1 = x1 - x2;
                      Real dx2 = x3 - x2;
                      Real dy1 = y1 - y2;
                      Real dy2 = y3 - y2;

            // determinants
                      Real gtop    = dx3 * dy2 - dx2 * dy3;
                      Real htop    = dx1 * dy3 - dx3 * dy1;
                      Real bottom = dx1 * dy2 - dx2 * dy1;

            if (!bottom)     return FALSE;
                      bottom =          1.0 / bottom;

            Real g = gtop*bottom;
                      Real h = htop*bottom;

            Real a = x1 - x0 + g * x1;
                      Real b = x3 - x0 + h * x3;
                      Real d = y1 - y0 + g * y1;
                      Real e = y3 - y0 + h * y3;

            SQ->m0 = a;   SQ->m1 = d;   SQ->m3 = g;
                      SQ->m4 = b;   SQ->m5 = e;   SQ->m7 = h;
                      SQ->m12 = x0; SQ->m13 = y0; SQ->m15 = 1.0f;
                 }
                 // Invert
                 //*SQ =     !(*SQ);
                 return TRUE;
            }
            // Calculate matrix for quad to unit-square mapping
            //                     - vertices        - square->quad transform
            //*---------------------------------------------------------------------------*
            void QuadToSquare(Real quad[4][2], Matrix2D* SQ)
            //*---------------------------------------------------------------------------*
            {
                 if (!SquareToQuad(quad, SQ))     return;

            // invert through adjoint
                 Real a = SQ->m0, d = SQ->m1, g = SQ->m3;
                 Real b = SQ->m4, e = SQ->m5, h = SQ->m7;
                 Real c = SQ->m12, f = SQ->m13;

            Real A = e - f * h;
                 Real B = c * h - b;
                 Real C = b * f - c * e;
                 Real D = f * g - d;
                 Real E = a - c * g;
                 Real F = c * d - a * f;
                 Real G = d * h - e * g;
                 Real H = b * g - a * h;
                 Real I = a * e - b * d;

            // Probably unnecessary since 'I' is also scaled by the determinant,
                 //   and 'I' scales the homogeneous coordinate, which, in turn,
                 //   scales the X,Y coordinates.
                 // Determinant =   a * (e - f * h) + b * (f * g - d) + c * (d * h - e * g);
                 Real idet = 1.0f / (a * A           + b * D           + c * G);

            SQ->m0 = A*idet; SQ->m1 = D*idet; SQ->m3 = G*idet;
                 SQ->m4 = B*idet; SQ->m5 = E*idet; SQ->m7 = H*idet;
                 SQ->m12 = C*idet; SQ->m13 = F*idet; SQ->m15 = I*idet;
            }

            // METHODS: TestingPlugin
            // Execute
            //*---------------------------------------------------------------------------*
            Bool TestingPlugin::Execute(BaseDocument* doc)
            //*---------------------------------------------------------------------------*
            {
                 PolygonObject*     op =     PolygonObject::Alloc(4L, 1L);
                 if (!op)                    return FALSE;
                 doc->InsertObject(op, NULL, NULL, FALSE);
                 CPolygon*          pa =     op->GetPolygonW();
                 Vector*               va =     op->GetPointW();
                 if (!(pa && va))          return FALSE;
                 pa->a =                         0L;
                 pa->b =                         2L;
                 pa->c =                         3L;
                 pa->d =                         1L;
                 /*
                 va[0] =                         Vector(-25.0f, -96.593f, 6.699f);
                 va[1] =                         Vector(-25.882f, -96.593f, 0.0f);
                 va[2] =                         Vector(-48.296f, -86.603f, 12.941f);
                 va[3] =                         Vector(-50.0f, -86.603f, 0.0f);
                 */
                 va[0] =                         Vector(35.355f, -70.711f, -61.237f);
                 va[1] =                         Vector(50.0f, -70.711f, -50.0f);
                 va[2] =                         Vector(43.301f, -50.0f, -75.0f);
                 va[3] =                         Vector(61.237f, -50.0f, -61.237f);
                 op->Message(MSG_UPDATE);

            // Test
                 // tv MUST BE IN POLYGON ORDER!
                 Vector     tv0 =               va[pa->a];
                 Vector     tv1 =               va[pa->b];
                 Vector     tv2 =               va[pa->c];
                 Vector     tv3 =               va[pa->d];
                 // Center of polygon
                 Vector     center =          (tv0+tv1+tv2+tv3) * 0.25f;
                 // Move polygon to world 0,0,0
                 tv0 -=                         center;
                 tv1 -=                         center;
                 tv2 -=                         center;
                 tv3 -=                         center;
                 // Rotate polygon so that normal made coincident with +Y axis and 0->1 vertices are horizontal on X-Z plane
                 Vector     u =                    !(tv1-tv0);
                 Vector     n =                    !((tv1-tv3)%(tv2-tv0));
                 Vector     v =                    !(u%n);
                 Matrix     m;
                 m.v1 =                         Vector(u.x, n.x, v.x);
                 m.v2 =                         Vector(u.y, n.y, v.y);
                 m.v3 =                         Vector(u.z, n.z, v.z);
                 va[pa->a] =                    tv0 * m;
                 va[pa->b] =                    tv1 * m;
                 va[pa->c] =                    tv2 * m;
                 va[pa->d] =                    tv3 * m;

            // Transform quad to unit square
                 // - Reverse order since C4D uses clockwise and everyone else uses counter-clockwise
                 tv0 =                         va[pa->a];
                 tv1 =                         va[pa->d];
                 tv2 =                         va[pa->c];
                 tv3 =                         va[pa->b];
                 Real     qi[4][2];
                 qi[0][0] =     tv0.x; qi[0][1] =     tv0.z;
                 qi[1][0] =     tv1.x; qi[1][1] =     tv1.z;
                 qi[2][0] =     tv2.x; qi[2][1] =     tv2.z;
                 qi[3][0] =     tv3.x; qi[3][1] =     tv3.z;
                 Matrix2D     T;
                 QuadToSquare(qi, &T;);
                 // Yes!
                 va[pa->a] =               tv0 * T;
                 va[pa->d] =               tv1 * T;
                 va[pa->c] =               tv2 * T;
                 va[pa->b] =               tv3 * T;

            op->Message(MSG_UPDATE);
                 EventAdd();
                 return TRUE;
            }

            //*---------------------------------------------------------------------------*
            LONG TestingPlugin::GetState(BaseDocument* doc)
            //*---------------------------------------------------------------------------*
            {
                 return CMD_ENABLED;
            }

            // Global Registrant Method for TestPlugin plugin
            //*---------------------------------------------------------------------------*
            Bool RegisterTestPluginCommand()
            //*---------------------------------------------------------------------------*
            {
                 return RegisterCommandPlugin(ID_TESTPLUGIN, "TestPlugin", 0, NULL, "TestPlugin", gNew TestingPlugin);
            }

            1 Reply Last reply Reply Quote 0
            • First post
              Last post