moldpers.cpp

Go to the documentation of this file.
00001 // $Id: moldpers.cpp 1282 2006-06-09 09:46:49Z alex $
00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
00003 ================================XARAHEADERSTART===========================
00004  
00005                Xara LX, a vector drawing and manipulation program.
00006                     Copyright (C) 1993-2006 Xara Group Ltd.
00007        Copyright on certain contributions may be held in joint with their
00008               respective authors. See AUTHORS file for details.
00009 
00010 LICENSE TO USE AND MODIFY SOFTWARE
00011 ----------------------------------
00012 
00013 This file is part of Xara LX.
00014 
00015 Xara LX is free software; you can redistribute it and/or modify it
00016 under the terms of the GNU General Public License version 2 as published
00017 by the Free Software Foundation.
00018 
00019 Xara LX and its component source files are distributed in the hope
00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the
00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00022 See the GNU General Public License for more details.
00023 
00024 You should have received a copy of the GNU General Public License along
00025 with Xara LX (see the file GPL in the root directory of the
00026 distribution); if not, write to the Free Software Foundation, Inc., 51
00027 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
00028 
00029 
00030 ADDITIONAL RIGHTS
00031 -----------------
00032 
00033 Conditional upon your continuing compliance with the GNU General Public
00034 License described above, Xara Group Ltd grants to you certain additional
00035 rights. 
00036 
00037 The additional rights are to use, modify, and distribute the software
00038 together with the wxWidgets library, the wxXtra library, and the "CDraw"
00039 library and any other such library that any version of Xara LX relased
00040 by Xara Group Ltd requires in order to compile and execute, including
00041 the static linking of that library to XaraLX. In the case of the
00042 "CDraw" library, you may satisfy obligation under the GNU General Public
00043 License to provide source code by providing a binary copy of the library
00044 concerned and a copy of the license accompanying it.
00045 
00046 Nothing in this section restricts any of the rights you have under
00047 the GNU General Public License.
00048 
00049 
00050 SCOPE OF LICENSE
00051 ----------------
00052 
00053 This license applies to this program (XaraLX) and its constituent source
00054 files only, and does not necessarily apply to other Xara products which may
00055 in part share the same code base, and are subject to their own licensing
00056 terms.
00057 
00058 This license does not apply to files in the wxXtra directory, which
00059 are built into a separate library, and are subject to the wxWindows
00060 license contained within that directory in the file "WXXTRA-LICENSE".
00061 
00062 This license does not apply to the binary libraries (if any) within
00063 the "libs" directory, which are subject to a separate license contained
00064 within that directory in the file "LIBS-LICENSE".
00065 
00066 
00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
00068 ----------------------------------------------
00069 
00070 Subject to the terms of the GNU Public License (see above), you are
00071 free to do whatever you like with your modifications. However, you may
00072 (at your option) wish contribute them to Xara's source tree. You can
00073 find details of how to do this at:
00074   http://www.xaraxtreme.org/developers/
00075 
00076 Prior to contributing your modifications, you will need to complete our
00077 contributor agreement. This can be found at:
00078   http://www.xaraxtreme.org/developers/contribute/
00079 
00080 Please note that Xara will not accept modifications which modify any of
00081 the text between the start and end of this header (marked
00082 XARAHEADERSTART and XARAHEADEREND).
00083 
00084 
00085 MARKS
00086 -----
00087 
00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
00089 designs are registered or unregistered trademarks, design-marks, and/or
00090 service marks of Xara Group Ltd. All rights in these marks are reserved.
00091 
00092 
00093       Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
00094                         http://www.xara.com/
00095 
00096 =================================XARAHEADEREND============================
00097  */
00098 // Perspective shape implementation
00099 
00100 /*
00101 */
00102 
00103 #include "camtypes.h"
00104 #include "moldpers.h"
00105 //#include "errors.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00106 //#include "paths.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00107 //#include "rndrgn.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00108 //#include "docview.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00109 //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00110 #include "blobs.h"
00111 //#include "justin.h"
00112 #include "moldedit.h"
00113 //#include "mike.h"
00114 
00115 #include <math.h>
00116 
00117 DECLARE_SOURCE("$Revision: 1282 $");
00118 
00119 CC_IMPLEMENT_MEMDUMP(GPerspective, GMould)
00120 CC_IMPLEMENT_DYNAMIC(MouldPerspective, MouldGeometry)
00121 CC_IMPLEMENT_DYNCREATE(RecordPerspectiveAction,Action)
00122 
00123 // Declare smart memory handling in Debug builds
00124 #define new CAM_DEBUG_NEW
00125 #define EPSILON 1e-10
00126 #define equal(a,b) ( fabs( (a) - (b) ) <= (EPSILON) )
00127 #define notequal(a,b) ( fabs( (a) - (b) ) > (EPSILON) )
00128 
00129 //static POINT InitialPerspective[PER_NUMCOORDS] = { {0,0}, {1,1} };
00130 //static RECT  InitialBounds = { 0,0,1,1 };
00131 
00132 
00133 /*******************************************************************************************
00134 
00135 >   virtual void MouldPerspective::MouldPerspective()
00136 
00137     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00138     Created:    12/12/94
00139     Inputs:     
00140     Purpose:    Perspective mould constructor
00141 
00142 ********************************************************************************************/
00143 
00144 MouldPerspective::MouldPerspective()
00145 {
00146     GridState = 0;          // 0 = Grid off
00147                             // 1 = Grid on
00148                             // 2 = Grid on but temporarily disabled
00149 }
00150 
00151 
00152 
00153 /*******************************************************************************************
00154 
00155 >   MouldPerspective::~MouldPerspective()
00156 
00157     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00158     Created:    12/12/94
00159     Inputs:     
00160     Purpose:    Perspective mould destructor
00161 
00162 ********************************************************************************************/
00163 
00164 MouldPerspective::~MouldPerspective()
00165 {
00166 }
00167 
00168 /*******************************************************************************************
00169 
00170 >   BOOL MouldPerspective::Validate(Path* const pPath, UINT32& errorID)
00171 
00172     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00173     Created:    11/02/95
00174     Inputs:     pPath   = the path to use for perspectivising
00175     Outputs:    errorID = an id of an error string reporting the problem when failed.
00176     Returns:    TRUE    - then the path can be used as an perspective manifold
00177                 FALSE   - then the path is not suitable for use as an perspective manifold
00178     Purpose:    This function checks whether the path given is suitabile for use as an
00179                 perspective manifold. Valid paths at present are any set of 5 path elements
00180                 starting with a moveto followed by 4 lineto elements which form a closed
00181                 loop without crossings.
00182 
00183 ********************************************************************************************/
00184 
00185 BOOL MouldPerspective::Validate(Path* const pPath, UINT32& errorID)
00186 {
00187     // check for a reasonable number of coordinates
00188     INT32 numc=pPath->GetNumCoords();
00189     if ((numc!=PER_NUMCOORDS+1))
00190     {
00191         errorID = _R(IDE_PERS_NUMCOORDERR);
00192         return FALSE;
00193     }
00194 
00195     // now we need a more complex check
00196     DocCoord* Coords = pPath->GetCoordArray();
00197     PathVerb* Verbs = pPath->GetVerbArray();
00198 
00199     // we need the first element to be a move to
00200     if (Verbs[0]!=PT_MOVETO)
00201     {
00202         errorID = _R(IDE_PERS_BADELEMENT);
00203         return FALSE;
00204     }
00205 
00206     // And the last coordinate must close the loop
00207     if (Coords[0]!=Coords[numc-1])
00208     {
00209         errorID = _R(IDE_PERS_NOTCLOSED);
00210         return FALSE;
00211     }
00212 
00213     INT32 i,j;
00214     // followed by all linetos
00215     for (i=1; i<numc; i++)
00216     {
00217         if ( (Verbs[i] & (~PT_CLOSEFIGURE))!=PT_LINETO )
00218         {
00219             errorID = _R(IDE_PERS_NOTALLLINES);
00220             return FALSE;
00221         }
00222     }
00223 
00224     // check no coordinates are the same
00225     for (i=1; i<numc; i++)
00226     {
00227         for (j=i+1; j<numc; j++)
00228         {
00229             if (Coords[i] == Coords[j])
00230             {
00231                 errorID = _R(IDE_PERS_COINCIDENT);
00232                 return FALSE;
00233             }
00234         }
00235     }
00236 
00237     // Make sure there's no folds either
00238     POINT* p = (POINT*)(Coords);
00239     if (!WillBeValid(p))
00240     {
00241         errorID = _R(IDE_PERS_CROSSING);
00242         return FALSE;
00243     }
00244 
00245     // All is well
00246     return TRUE;
00247 }
00248 
00249 
00250 /*******************************************************************************************
00251 
00252     BOOL MouldPerspective::WillBeValid(POINT* P)
00253 
00254     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00255     Created:    12/12/94
00256     Inputs:     P a pointer to a POINT array of coordinates
00257     Returns:    TRUE if the point set is valid
00258     Purpose:    Check whether the point array has any crossing and is thus unsuited for use
00259                 as a manifold
00260 
00261 ********************************************************************************************/
00262 
00263 BOOL MouldPerspective::WillBeValid(POINT* P)
00264 {
00265     INT32 MinX, MaxX, MinY, MaxY, Width, Depth ;
00266     DPOINT V0,V1,V2,V3;
00267 
00268     MinX = MaxX = P[0].x ;
00269     MinY = MaxY = P[0].y ;
00270     MinX = min( MinX, INT32(P[1].x) ) ; MaxX = max( MaxX, INT32(P[1].x) ) ;
00271     MinY = min( MinY, INT32(P[1].y) ) ; MaxY = max( MaxY, INT32(P[1].y) ) ;
00272     MinX = min( MinX, INT32(P[2].x) ) ; MaxX = max( MaxX, INT32(P[2].x) ) ;
00273     MinY = min( MinY, INT32(P[2].y) ) ; MaxY = max( MaxY, INT32(P[2].y) ) ;
00274     MinX = min( MinX, INT32(P[3].x) ) ; MaxX = max( MaxX, INT32(P[3].x) ) ;
00275     MinY = min( MinY, INT32(P[3].y) ) ; MaxY = max( MaxY, INT32(P[3].y) ) ;
00276     Width = MaxX-MinX ;
00277     Depth = MaxY-MinY ;
00278 
00279     if (Width==0 || Depth==0)
00280         return FALSE;
00281 
00282     V0.x = (double)(P[0].x-MinX)/Width ;
00283     V0.y = (double)(P[0].y-MinY)/Depth ;
00284     V1.x = (double)(P[1].x-MinX)/Width ;
00285     V1.y = (double)(P[1].y-MinY)/Depth ;
00286     V2.x = (double)(P[2].x-MinX)/Width ;
00287     V2.y = (double)(P[2].y-MinY)/Depth ;
00288     V3.x = (double)(P[3].x-MinX)/Width ;
00289     V3.y = (double)(P[3].y-MinY)/Depth ;
00290 
00291     BOOL F  =  (V1.x-V0.x)*(V3.y-V0.y) > (V1.y-V0.y)*(V3.x-V0.x) ;
00292     if ( F != ((V2.x-V1.x)*(V0.y-V1.y) > (V2.y-V1.y)*(V0.x-V1.x)) ) return FALSE ;
00293     if ( F != ((V3.x-V2.x)*(V1.y-V2.y) > (V3.y-V2.y)*(V1.x-V2.x)) ) return FALSE ;
00294     if ( F != ((V0.x-V3.x)*(V2.y-V3.y) > (V0.y-V3.y)*(V2.x-V3.x)) ) return FALSE ;
00295 
00296     return TRUE;
00297 }
00298 
00299 
00300 
00301 /*******************************************************************************************
00302 
00303 >   BOOL MouldPerspective::Define(Path* const pPath, DocRect* const pOrigBBox)
00304 
00305     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00306     Created:    2/12/94
00307     Inputs:     pPath     = the path to use for moulding
00308                 pOrigBBox = a pointer to the bounding box of the objects to be moulded
00309                           = NULL then the old bounding box will be assumed.
00310     returns:    TRUE    - then Define has succeded
00311                 FALSE   - then Define has failed to initialise the perspective mould
00312     Purpose:    This function sets the low level perspective state ready for calls to various
00313                 perspective path generation functions. It serves simply as a way of informing
00314                 the low level perspectiviser of the shape of the current manifold
00315 
00316 ********************************************************************************************/
00317 
00318 BOOL MouldPerspective::Define(Path* const pPath, DocRect* const pOrigBBox)
00319 {
00320     ERROR2IF(pPath==NULL && pOrigBBox==NULL, FALSE,"MouldPerspective::Define() called with NULL parameters");
00321 
00322     RECT ObjRect = BuildRectangle(pOrigBBox);
00323     
00324     // Save the current state incase we fail
00325     POINT TempArray[PER_NUMCOORDS];
00326     RECT TempRect=Perspective.GetSourceBBox();
00327     Perspective.CopyShape(TempArray);
00328 
00329     // if we're defining a new path then point at it
00330     POINT* pPoints = TempArray;
00331     if (pPath!=NULL)
00332         pPoints=(POINT*)pPath->GetCoordArray();
00333 
00334     // Define the new shape
00335     Perspective.Define(pPoints,&ObjRect,MouldThreshold);
00336 
00337     // now check it for validity
00338     if (!Perspective.Valid())
00339     {
00340         // if not valid replace the old data
00341         Perspective.Define(TempArray,&TempRect,MouldThreshold);
00342         return FALSE;
00343     }
00344         
00345     return TRUE;
00346 }
00347 
00348 
00349 
00350 /*******************************************************************************************
00351 
00352     RECT MouldPerspective::BuildShape(POINT* pPoints, DocRect* const pOrigBBox) 
00353 
00354     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00355     Created:    11/01/95
00356     Inputs:     pPoints     = a pointer to a array of INT32 coordinates
00357                 pOrigBBox   = a pointer to the bounding box of the objects to be moulded
00358                             = NULL then the old bounding box will be assumed.
00359     Returns:    TRUE    - then BuildShape has succeded
00360                 FALSE   - then BuildShape has failed to create the mould shape
00361     Purpose:    
00362 
00363 ********************************************************************************************/
00364 
00365 BOOL MouldPerspective::BuildShape(POINT* pPoints, DocRect* const pOrigBBox)
00366 {
00367     ERROR2IF(pPoints==NULL,FALSE,"MouldPerspective::BuildShape() called with NULL point list");
00368 
00369     RECT ObjRect = BuildRectangle(pOrigBBox);
00370 
00371     Perspective.Define(pPoints,&ObjRect,MouldThreshold);
00372 
00373     return TRUE;
00374 }
00375 
00376 
00377 
00378 /*******************************************************************************************
00379 
00380 >   RECT MouldPerspective::BuildRectangle(DocRect* const pOrigBBox) 
00381 
00382     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00383     Created:    11/01/95
00384     Inputs:     pOrigBBox = a pointer to the bounding box of the objects to be perspectivised
00385                           = NULL then the old bounding box will be assumed.
00386     Returns:    a RECT structure.           
00387     Purpose:    Build a RECT structure to pass to the low level perspective code. 
00388 
00389 ********************************************************************************************/
00390 
00391 RECT MouldPerspective::BuildRectangle(DocRect* const pOrigBBox)
00392 {
00393     RECT ObjRect;
00394     if (pOrigBBox!=NULL)
00395     {
00396         ObjRect.left    = pOrigBBox->lo.x;
00397         ObjRect.bottom  = pOrigBBox->lo.y;
00398         ObjRect.right   = pOrigBBox->hi.x;
00399         ObjRect.top     = pOrigBBox->hi.y;
00400     }
00401     else
00402         ObjRect = Perspective.GetSourceBBox();
00403 
00404     return ObjRect;
00405 }
00406 
00407 
00408 
00409 
00410 
00411 
00412 /*******************************************************************************************
00413 
00414 >   virtual BOOL MouldPerspective::MouldPathToPath(Path* pSourcePath, Path* pDestinPath)
00415 
00416     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00417     Created:    2/12/94
00418     Inputs:     pSourcePath = pointer to a path object to mould
00419                 pDestinPath = pointer to a path buffer to put the resulting moulded path in
00420     Outputs:    pDestinPath contains the moulded version of the path
00421     Returns:    TRUE    - if the mould was successfull
00422                 FALSE   - if no room to create the mould
00423     Purpose:    Using the defined Perspective, mould one path into another.
00424 
00425 ********************************************************************************************/
00426 
00427 BOOL MouldPerspective::MouldPathToPath(Path* pSourcePath, Path* pDestinPath)
00428 {
00429     ERROR2IF(pSourcePath==NULL, FALSE, "MouldPerspective::MouldPathToPath() passed a NULL source pointer");
00430     ERROR2IF(pDestinPath==NULL, FALSE, "MouldPerspective::MouldPathToPath() passed a NULL destin pointer");
00431 
00432     // get the source path data length
00433     DWORD ilength = (DWORD)pSourcePath->GetNumCoords();
00434 
00435     // if there's no input path, then there's no output path, and all is well.
00436     if (ilength<1)
00437         return TRUE;
00438 
00439     INT32 freespace = ilength*4;
00440     INT32 maxspace = ilength*16;
00441     BOOL ok;
00442     INT32 added;
00443 
00444     Path TempPath;
00445     if (!TempPath.Initialise(freespace,24))
00446         return FALSE;
00447 
00448     do
00449     {
00450         // get the source object and destin object path data
00451         POINT* icoords = (POINT*)pSourcePath->GetCoordArray();
00452         BYTE*  iverbs  = (BYTE*)pSourcePath->GetVerbArray();
00453         POINT* ocoords = (POINT*)TempPath.GetCoordArray();
00454         BYTE*  overbs  = (BYTE*)TempPath.GetVerbArray();
00455 
00456         // try to create an enveloped path
00457         added = Perspective.FitPath(icoords,iverbs,ilength,ocoords,overbs,freespace);
00458 
00459         if (added==-1)
00460         {
00461             freespace*=2;
00462             // create what we think will be enough space for the output path
00463             ok = TempPath.EnsureVolume(freespace);
00464             if (!ok) 
00465                 return FALSE;
00466         }
00467 
00468     } while ((added==-1) && freespace<=maxspace);
00469 
00470     // if we've failed to create the perspectivised object then tidy up
00471     if (added<=1)
00472         return FALSE;
00473 
00474     // now lets set up the new flags array
00475     ok = TempPath.ExternalArraysReplaced(added);
00476     if (ok)
00477         TempPath.InitialiseFlags(0,added);
00478 
00479     if (ok)
00480     {
00481 
00482 /* Path trimming, temporarily removed as doesn't fix the showstopper.
00483 
00484         // Ok check for rampant null elements in this path
00485         DocCoord* Coords;
00486         PathVerb* Verbs;
00487         PathFlags* Flags;
00488         PathVerb CurVerb;
00489         INT32 i,lmi;
00490         DocCoord lm;
00491 
00492         TempPath.GetPathArrays(&Verbs,&Coords,&Flags);
00493 
00494         for (i=0; i<added; i++)
00495         {
00496             CurVerb = Verbs[i] & ~PT_CLOSEFIGURE;
00497             if (CurVerb==PT_MOVETO)
00498             {
00499                 lm=Coords[i];
00500                 lmi=i;
00501             }
00502 
00503             if (CurVerb==PT_BEZIERTO)
00504             {
00505                 if (Verbs[i+2] & PT_CLOSEFIGURE)
00506                 {
00507                     DocCoord p0,p1,p2;
00508                     p0 = Coords[i];
00509                     p1 = Coords[i+1];
00510                     p2 = Coords[i+2];
00511                     if ((p0.x==p1.x) && (p1.x==p2.x) && (p2.x==lm.x) &&
00512                         (p0.y==p1.y) && (p1.y==p2.y) && (p2.y==lm.y) && 
00513                         (i-lmi)>1)
00514                     {
00515                         // We can delete this element!
00516                         Verbs[i-1] |= PT_CLOSEFIGURE;
00517                         if (TempPath.DeleteSection(i,3))
00518                         {
00519                             added-=3;
00520                             i-=3;
00521                         }
00522                         else
00523                             i=added;
00524                     }
00525                 }
00526                 i+=2;
00527             }
00528         }
00529 */
00530         ok = pDestinPath->CloneFrom(TempPath);
00531     }
00532 
00533     return ok;
00534 }
00535 
00536 
00537 
00538 /*******************************************************************************************
00539 
00540 >   virtual BOOL MouldPerspective::MouldPoint(DocCoord p, DocCoord& q)
00541 
00542     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00543     Created:    2/12/94
00544     Inputs:     p = the coordinate to be transformed
00545     Outputs:    q = the transformed version of the coordinate
00546     Returns:    TRUE if the point has been transformed
00547                 FALSE if q==p
00548     Purpose:    Using the defined perspective, this function takes the input coordinate
00549                 and calculates its transformed version.
00550 
00551 ********************************************************************************************/
00552 
00553 BOOL MouldPerspective::MouldPoint(DocCoord p,DocCoord& q)
00554 {
00555     // I aught to check that the point as contained within the source rectangle
00556     // bbox and do something about it if not. But what to do?
00557     // It turns out that perspective transforms behave sensibly for points
00558     // outside the source bbox so we can remove the following checks.
00559 /*
00560     RECT rect = Perspective.GetSourceBBox();
00561     if  ((p.x<rect.left) || (p.x>rect.right) ||
00562         (p.y<rect.bottom) || (p.y>rect.top))
00563     {
00564         q=p;
00565         return;
00566     }
00567 */
00568     POINT r,s;
00569 
00570     r.x = p.x;
00571     r.y = p.y;
00572 
00573     Perspective.FitPoint(r,s);
00574 
00575     q.x = s.x;
00576     q.y = s.y;
00577 
00578     return TRUE;
00579 }
00580 
00581 
00582 
00583 
00584 /*******************************************************************************************
00585 
00586 >   virtual BOOL MouldPerspective::MouldBitmapToTile(Blit* pSourceBlit, Blit* pDestinBlit)
00587 
00588     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00589     Created:    2/12/94
00590     Inputs:     pSourceBlit = pointer to a bitmap to Perspective
00591                 pDestinBlit = pointer to an output tile to mould into
00592     Outputs:    pDestinBlit = Perspectived version of the bitmap
00593     Returns:    TRUE    - if the mould was successfull
00594                 FALSE   - if no room to create the mould
00595     Purpose:    Create an Perspectived version of a bitmap, ready to be rendered to a device
00596 
00597 ********************************************************************************************/
00598 
00599 BOOL MouldPerspective::MouldBitmapToTile(KernelBitmap* pSourceBlit, KernelBitmap* pDestinBlit)
00600 {
00601     // currently not implemented
00602     return FALSE;
00603 }
00604 
00605 
00606 /*******************************************************************************************
00607 
00608 >   virtual void MouldPerspective::MouldPathRender(Path* pPath, RenderRegion* pRegion)
00609 
00610     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00611     Created:    2/12/94
00612     Inputs:     pPath   = pointer to a path to perspectivise
00613                 pRegion = pointer to a region to render into
00614     Purpose:    Render a given path using the current perspective settings, to the output
00615                 region
00616 
00617 ********************************************************************************************/
00618 
00619 void MouldPerspective::MouldPathRender(Path* pPath, RenderRegion* pRegion)
00620 {
00621 }
00622 
00623 
00624 
00625 
00626 /*******************************************************************************************
00627 
00628 >   virtual void MouldPerspective::MouldBitmapRender(KernelBitmap* pBlit,
00629                                                      DocCoord* pParallel,
00630                                                      RenderRegion* pRegion)
00631 
00632     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00633     Created:    2/12/94
00634     Inputs:     pBlit       = pointer to a kernel bitmap
00635                 pParallel   = pointer to a four point parallelogram
00636                 pRegion     = pointer to a region to render into
00637     Purpose:
00638 
00639 ********************************************************************************************/
00640 
00641 void MouldPerspective::MouldBitmapRender(KernelBitmap* pBlit, 
00642                                          DocCoord* Parallel,
00643                                          RenderRegion* pRegion)
00644 {
00645     pRegion->SaveContext();
00646 
00647     // No lines on the rectangle
00648     pRegion->SetLineColour(COLOUR_TRANS);
00649 
00650     pRegion->RestoreContext();
00651 }
00652 
00653 /*******************************************************************************************
00654 
00655 >   virtual void MouldPerspective::ToggleControlBlobs(Spread* pSpread)
00656 
00657     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00658     Created:    2/12/94
00659     Inputs:     pSpread = pointer to a spread to render into
00660     Purpose:    
00661 
00662 ********************************************************************************************/
00663 
00664 void MouldPerspective::ToggleControlBlobs(Spread* pSpread)
00665 {
00666     // if we're in a suspended state do nothing!
00667     if (GridState>1) return;
00668     // toggle the grid state.
00669     GridState ^= 1;
00670     if (pSpread!=NULL)
00671         RenderGrid(pSpread);
00672 }
00673 
00674 /*******************************************************************************************
00675 
00676 >   virtual void MouldPerspective::Enable/DisableControlBlobs()
00677 
00678     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00679     Created:    2/12/94
00680     Inputs:     -
00681     Purpose:    Used when an perspective is undergoing a drag, we disable normal blob rendering
00682                 
00683 ********************************************************************************************/
00684 
00685 void MouldPerspective::EnableControlBlobs()
00686 {
00687     if (GridState>1) GridState--;
00688 }
00689 
00690 void MouldPerspective::DisableControlBlobs()
00691 {
00692     if (GridState>0) GridState++;
00693 }
00694 
00695 
00696 /*******************************************************************************************
00697 
00698 >   virtual void MouldPerspective::RenderControlBlobs(RenderRegion* pRegion)
00699 
00700     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00701     Created:    2/12/94
00702     Inputs:     pRegion = pointer to a region to render into
00703     Purpose:    Draw on the perspective grid points on if they are supposed to be shown.
00704 
00705 ********************************************************************************************/
00706 
00707 void MouldPerspective::RenderControlBlobs(RenderRegion* pRegion)
00708 {
00709 #if !defined(EXCLUDE_FROM_RALPH)
00710     ERROR3IF(pRegion==NULL,"MouldPerspective::RenderControlBlobs passed a NULL region");
00711     if (pRegion==NULL)
00712         return;
00713     if (GridState==1)
00714         RenderGrid(pRegion);
00715 
00716     RenderVanishingPoints(pRegion);
00717 #endif
00718 }
00719 
00720 
00721 /*******************************************************************************************
00722 
00723 >   virtual void MouldPerspective::RenderDragBlobs(RenderRegion* pRegion)
00724 
00725     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00726     Created:    2/12/94
00727     Inputs:     pRegion = pointer to a region to render into
00728     Purpose:    Draw on the perspective grid points on if they are supposed to be shown.
00729 
00730 ********************************************************************************************/
00731 
00732 void MouldPerspective::RenderDragBlobs(Spread* pSpread)
00733 {
00734 #if !defined(EXCLUDE_FROM_RALPH)
00735     ERROR3IF(pSpread==NULL,"MouldPerspective::RenderControlBlobs passed a NULL spread");
00736     if (pSpread==NULL)
00737         return;
00738     if (GridState>0)
00739         RenderGrid(pSpread);
00740 
00741     RenderVanishingPoints(pSpread);
00742 #endif
00743 }
00744 
00745 /*******************************************************************************************
00746 
00747 >   void MouldPerspective::RenderGrid(Spread* pSpread)
00748 
00749     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00750     Created:    2/12/94
00751     Inputs:     pSpread = pointer to a spread to render into
00752     Purpose:    Draw on the perspective grid points on if they are supposed to be shown.
00753 
00754 ********************************************************************************************/
00755 
00756 void MouldPerspective::RenderGrid(Spread* pSpread)
00757 {
00758 #if !defined(EXCLUDE_FROM_RALPH)
00759     ERROR3IF(pSpread==NULL,"MouldPerspective::RenderGrid() passed a NULL spread");
00760     DocRect Rect = Perspective.GetBoundingRect();
00761     RenderRegion* pRegion = DocView::RenderOnTop( &Rect, pSpread, ClippedEOR );
00762     while ( pRegion )
00763     {
00764         RenderGrid(pRegion);
00765         pRegion = DocView::GetNextOnTop(NULL);
00766     }   
00767 #endif
00768 }
00769 
00770 
00771 /*******************************************************************************************
00772 
00773 >   virtual void MouldPerspective::RenderGrid(RenderRegion* pRegion)
00774 
00775     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00776     Created:    2/12/94
00777     Inputs:     pRegion = pointer to a region to render into
00778     Purpose:    Draw on the perspective vanishing points if they intersect the current
00779                 region
00780 
00781 ********************************************************************************************/
00782 
00783 void MouldPerspective::RenderGrid(RenderRegion* pRegion)
00784 {
00785 #if !defined(EXCLUDE_FROM_RALPH)
00786     ERROR3IF(pRegion==NULL,"MouldPerspective::RenderBlobs() passed a NULL region");
00787     if (pRegion==NULL) return;
00788 
00789     // get the base class to render
00790     MouldGeometry::RenderControlBlobs(pRegion);
00791     // Now render any vanishing points
00792     pRegion->SetLineWidth(0);                               // Means single-pixel lines
00793     pRegion->SetLineColour(GREEN);
00794     pRegion->SetFillColour(GREEN);
00795     // now render the grid
00796     RenderGridPoints(pRegion);
00797 #endif
00798 }
00799 
00800 
00801 
00802 /*******************************************************************************************
00803 
00804 >   void MouldPerspective::RenderGridPoints(RenderRegion* pRegion)
00805 
00806     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00807     Created:    04/01/95
00808     Inputs:     pRegion = pointer to a region to render into
00809     Purpose:    Draw all the prespective grid points on if they are supposed to be shown.
00810 
00811 ********************************************************************************************/
00812 
00813 void MouldPerspective::RenderGridPoints(RenderRegion* pRegion)
00814 {
00815 #if !defined(EXCLUDE_FROM_RALPH)
00816     // We need to scan through the origin bounding rectangle, calculating
00817     // an MxN rectangle of points, transforming them all and rendering them to the region
00818 
00819     INT32 p0 = 8;
00820     INT32 p1 = 4*p0;
00821     INT32 a,b,x,y;
00822     POINT sU,dU;
00823     DocCoord pU;
00824     RECT Bounds = Perspective.GetSourceBBox();
00825     INT32 dX = Bounds.right - Bounds.left;
00826     INT32 dY = Bounds.top - Bounds.bottom;
00827 
00828     for (a=1; a<p0; a++)
00829     {
00830         x = Bounds.left + a*dX/p0;
00831         y = Bounds.bottom + a*dY/p0;
00832 
00833         for (b=1; b<p1; b++)
00834         {
00835             if (b % (p1/p0))
00836             {
00837                 sU.x = Bounds.left + b*dX/p1;
00838                 sU.y = y;
00839                 Perspective.FitPoint(sU,dU);
00840                 pU.x = dU.x;
00841                 pU.y = dU.y;
00842                 pRegion->DrawPixel(pU); 
00843             }
00844 
00845             sU.x = x;
00846             sU.y = Bounds.bottom + b*dY/p1;
00847             Perspective.FitPoint(sU,dU);
00848             pU.x = dU.x;
00849             pU.y = dU.y;
00850             pRegion->DrawPixel(pU);
00851         }
00852     }
00853 #endif
00854 }
00855 
00856 
00857 /*******************************************************************************************
00858 
00859 >   void MouldPerspective::RenderVanishingPoints(Spread* pSpread)
00860 
00861     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00862     Created:    25/01/95
00863     Inputs:     pSpread = pointer to a spread to render into
00864     Purpose:    Draw on the perspective vanishing points on.
00865 
00866 ********************************************************************************************/
00867 
00868 void MouldPerspective::RenderVanishingPoints(Spread* pSpread)
00869 {
00870 #if !defined(EXCLUDE_FROM_RALPH)
00871     ERROR3IF(pSpread==NULL,"MouldPerspective::RenderVanishingPoints() passed a NULL spread");
00872     DocCoord v0,v1;
00873     GetVanishingPoints(v0,v1);
00874     RenderVanishingPoint(pSpread,v0);
00875     RenderVanishingPoint(pSpread,v1);
00876 #endif
00877 }
00878 
00879 
00880 /*******************************************************************************************
00881 
00882 >   void MouldPerspective::RenderVanishingPoint(Spread* pSpread, const DocCoord& dcPos)
00883 
00884     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00885     Created:    25/01/95
00886     Inputs:     dcPos = a doc coord at which to display the vanish point
00887     Purpose:    Draws a particular prespective vanishing point on.
00888 
00889 ********************************************************************************************/
00890 
00891 void MouldPerspective::RenderVanishingPoint(Spread* pSpread, const DocCoord& dcPos)
00892 {
00893 #if !defined(EXCLUDE_FROM_RALPH)
00894     DocRect Rect;
00895     if (dcPos.x!=PER_UNDEFINED)
00896     {
00897         Rect=CalcBlobClipRect(dcPos);
00898         RenderRegion* pRegion = DocView::RenderOnTop(&Rect, pSpread, ClippedEOR );
00899         while ( pRegion )
00900         {
00901             pRegion->SetLineColour(COLOUR_XORSELECT);
00902 PORTNOTE("other", "DrawBitmapBlob removed");
00903 //          pRegion->DrawBitmapBlob(dcPos, _R(IDBMP_HANDLE_CENTRE));
00904             pRegion = DocView::GetNextOnTop(NULL);
00905         }   
00906     }
00907 #endif
00908 }
00909 
00910 /*******************************************************************************************
00911 
00912 >   void MouldPerspective::RenderVanishingPoints(RenderRegion* pRegion)
00913 
00914     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00915     Created:    25/01/95
00916     Inputs:     pRegion = pointer to a region to render into
00917     Purpose:    Draws the prespective vanishing points on.
00918 
00919 ********************************************************************************************/
00920 
00921 void MouldPerspective::RenderVanishingPoints(RenderRegion* pRegion)
00922 {
00923 #if !defined(EXCLUDE_FROM_RALPH)
00924     pRegion->SetLineColour(COLOUR_XORSELECT);
00925 
00926     // first read the vanishing point positions
00927     DocCoord v0,v1;
00928     GetVanishingPoints(v0,v1);
00929 
00930 PORTNOTE("other", "DrawBitmapBlob removed");
00931 //  if (v0.x!=PER_UNDEFINED)
00932 //      pRegion->DrawBitmapBlob(v0, _R(IDBMP_HANDLE_CENTRE));
00933 //  if (v1.x!=PER_UNDEFINED)
00934 //      pRegion->DrawBitmapBlob(v1, _R(IDBMP_HANDLE_CENTRE));
00935 #endif
00936 }
00937 
00938 
00939 void MouldPerspective::ShowVPoints()
00940 {
00941     DocCoord v0,v1;
00942     GetVanishingPoints(v0,v1);
00943     // TRACEUSER( "Mike", _T("V0=(%d,%d)\n"),v0.x,v0.y);
00944     // TRACEUSER( "Mike", _T("V1=(%d,%d)\n"),v1.x,v1.y);
00945 }
00946 
00947 
00948 /********************************************************************************************
00949 
00950 >   DocRect MouldPerspective::CalcBlobClipRect(const DocCoord& dcPos)
00951 
00952     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00953     Created:    25/01/95
00954     Inputs:     dcPos       the centre of the blob that the clipping rectangle will surround
00955     Outputs:    -
00956     Returns:    A clipping rectangle for use by RenderDragBlobs.
00957     Purpose:    Constructs a rectangle that surrounds the given point 
00958     Errors:     -
00959 
00960 ********************************************************************************************/
00961 
00962 DocRect MouldPerspective::CalcBlobClipRect(const DocCoord& dcPos)
00963 {
00964 #if !defined(EXCLUDE_FROM_RALPH)
00965     BlobManager* pBlobManager = GetApplication()->GetBlobManager();
00966     INT32 nSize = pBlobManager->GetBlobSize() + 2;
00967     return DocRect(DocCoord(dcPos.x - nSize, dcPos.y - nSize),
00968                    DocCoord(dcPos.x + nSize, dcPos.y + nSize));
00969 #else
00970     return DocRect(0,0,0,0);
00971 #endif
00972 }
00973 
00974 
00975 /********************************************************************************************
00976 
00977 >   virtual DocRect MouldPerspective::GetBlobBoundingRect()
00978 
00979     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00980     Created:    20/12/94
00981     Returns:    DocRect - Returns the bounding rect of the path and its blobs
00982     Purpose:    This calculates the bounding box of the mould and adds in the influence of
00983                 the selection blobs. It does not consider if the blobs are visible or not,
00984                 it just gives the bounding box that they would occupy if they were visible
00985 
00986 ********************************************************************************************/
00987 
00988 DocRect MouldPerspective::GetBlobBoundingRect()
00989 {
00990 #if !defined(EXCLUDE_FROM_RALPH)
00991     DocCoord v0,v1;
00992     GetVanishingPoints(v0,v1);
00993 
00994     DocRect Rect;
00995 
00996     if (v0.x!=PER_UNDEFINED)
00997         Rect=Rect.Union(CalcBlobClipRect(v0));
00998 
00999     if (v1.x!=PER_UNDEFINED)
01000         Rect=Rect.Union(CalcBlobClipRect(v1));
01001 
01002     return Rect;
01003 #else
01004     return DocRect(0,0,0,0);
01005 #endif
01006 }
01007 
01008 
01009 /********************************************************************************************
01010 
01011 >   void MouldPerspective::GetVanishingPoints(DocCoord& p0, DocCoord& p1)
01012 
01013     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01014     Created:    25/01/95
01015     Inputs:
01016     Outputs:    p0 = the first vanishing point position  (0x80000000 if none existant)
01017                 p1 = the second vanishing point position (0x80000000 if none existant)
01018     Returns:    
01019     Purpose:    Reads the values of this defined perspectives vanishing points.
01020 
01021 ********************************************************************************************/
01022 
01023 void MouldPerspective::GetVanishingPoints(DocCoord& p0, DocCoord& p1)
01024 {
01025     POINT v0,v1;
01026     Perspective.VanishingPoints(v0,v1);
01027     p0.x=v0.x; p0.y=v0.y;
01028     p1.x=v1.x; p1.y=v1.y;
01029 }
01030 
01031 
01032 /********************************************************************************************
01033 
01034 >   BOOL MouldPerspective::MoveVanishingPoint(DocCoord OldPoint, DocCoord& NewPoint)
01035 
01036     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01037     Created:    25/01/95
01038     Inputs:     OldPoint = A last known vanishing point position
01039                 NewPoint = What should hopefully become a new position
01040     Outputs:    NewPoint = The new point will be updated to hold the actual position of
01041                            the vanishing point. It may be slightly different from NewPoint
01042                            due to rounding error.
01043     Returns:    TRUE if the mould vanishing point has been altered, 
01044                 FALSE if no change has occured, due to either
01045                 (1) the old vanishing point could not be located
01046                 (2) the new vanishing point causes the perspective map to become invalid
01047     Purpose:    Moves a vanishing point from OldPoint to NewPoint and redefines the
01048                 perspective shape to suit.
01049                 If the perspective moves into an invalid position the routine will return
01050                 FALSE and leave the stored perspective as was.
01051 
01052 ********************************************************************************************/
01053 
01054 BOOL MouldPerspective::MoveVanishingPoint(DocCoord OldPoint, DocCoord& NewPoint)
01055 {
01056 #if !defined(EXCLUDE_FROM_RALPH)
01057     BOOL Flag;
01058     if (OldPoint.x==PER_UNDEFINED || OldPoint.y==PER_UNDEFINED)
01059         return FALSE;
01060 
01061     POINT p;
01062     p.x=OldPoint.x;
01063     p.y=OldPoint.y;
01064 
01065     if (!Perspective.WhichVanishingPoint(p, Flag))
01066         return FALSE;
01067 
01068     // Save the current state incase we fail
01069     POINT TempArray[PER_NUMCOORDS];
01070     Perspective.CopyShape(TempArray);
01071     POINT TempArray1[PER_NUMCOORDS];
01072     Perspective.CopyShape(TempArray1);
01073     INT32 SCode = Perspective.GetVPointState();
01074 
01075     p.x=NewPoint.x;
01076     p.y=NewPoint.y;
01077 
01078     Perspective.DragVanishingPoints(p,Flag,TempArray1);
01079     BuildShape(TempArray1,NULL);
01080     INT32 ECode = Perspective.GetVPointState();
01081 
01082     // now check it for validity
01083     if ((!Perspective.Valid()) || (SCode!=ECode))
01084     {
01085         // if not valid replace the old data
01086         BuildShape(TempArray,NULL);
01087         return FALSE;
01088     }
01089 
01090     DocCoord v0,v1;
01091     GetVanishingPoints(v0,v1);
01092     Flag ? (NewPoint=v1) : (NewPoint=v0);
01093 #endif
01094     return TRUE;
01095 }
01096 
01097 
01098 
01099 /********************************************************************************************
01100 
01101 >   void MouldPerspective::CopyShape(DocCoord* pCoords)
01102 
01103     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01104     Created:    30/01/95
01105     Inputs:     pCoords = A pointer to an array of doc coords
01106     Outputs:    pCoords contains the five coordinates of the perspective shape
01107     Purpose:    Make a copy of the current perspective shape, placing the output coords
01108                 in pCoords, most likely a path coordinate array.
01109                 Note, the routine expects pCoords to point to an array of at least five
01110                 coordinates.
01111 
01112 ********************************************************************************************/
01113 
01114 void MouldPerspective::CopyShape(DocCoord* pCoords)
01115 {
01116     POINT TempArray[PER_NUMCOORDS];
01117     Perspective.CopyShape(TempArray);
01118 
01119     INT32               i;
01120     for( i = 0; i < PER_NUMCOORDS; i++ )
01121     {
01122         pCoords[i].x = TempArray[i].x;
01123         pCoords[i].y = TempArray[i].y;
01124     }
01125 
01126     // copy the last coordinate in to.
01127     pCoords[i].x=TempArray[0].x;
01128     pCoords[i].y=TempArray[0].y;
01129 }
01130 
01131 
01132 /********************************************************************************************
01133 
01134 >   virtual MouldGeometry* MouldPerspective::MakeCopy()
01135 
01136     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01137     Created:    11/12/94
01138     Inputs:
01139     Outputs:    a pointer to a new mould perspective object
01140                 NULL if unable to create the object.
01141     Purpose:    Make a copy of this mould perspective object and return it.
01142 
01143 ********************************************************************************************/
01144 
01145 MouldGeometry* MouldPerspective::MakeCopy()
01146 {
01147     // create a new shape
01148     MouldPerspective* pShape = new MouldPerspective;
01149     if (pShape == NULL)
01150         return NULL;
01151 
01152     BOOL ok = CopyContents(pShape);
01153     if (!ok)
01154     {
01155         delete pShape;
01156         return NULL;
01157     }
01158 
01159     return (pShape);
01160 }
01161 
01162 
01163 /********************************************************************************************
01164 
01165 >   BOOL MouldPerspective::CopyContents(MouldPerspective* pPerspective)
01166 
01167     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01168     Created:    17/01/95
01169     Inputs:     pPerspective = a pointer to a copy of a perspective object.
01170     Outputs:    
01171     Returns:    TRUE if the data has been copied correctly
01172                 FALSE if failed
01173     Purpose:    Make a copy of this mould perspective class private data
01174 
01175 ********************************************************************************************/
01176 
01177 BOOL MouldPerspective::CopyContents(MouldPerspective* pPerspective)
01178 {
01179     ERROR3IF(pPerspective==NULL, "MouldPerspective::CopyContents() passed a null pointer");
01180     // ask the base class to copy its bits first
01181     if (!MouldGeometry::CopyContents(pPerspective))
01182         return FALSE;
01183 
01184     // now lets copy data about ourselves
01185     POINT TempArray[PER_NUMCOORDS];
01186     RECT TempRect = Perspective.GetSourceBBox();
01187     DocRect Rect = ConvRectToDocRect(TempRect);
01188     Perspective.CopyShape(TempArray);
01189 
01190     // define this shape with the details
01191     return (pPerspective->BuildShape(TempArray, &Rect));
01192 }
01193 
01194 
01195 /********************************************************************************************
01196 
01197 >   DocRect MouldPerspective::GetSourceRect()
01198 
01199     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01200     Created:    17/01/95
01201     Inputs:     
01202     Returns:    a doc rect.
01203     Purpose:    Return the current definition of the mould perspective source rectangle.
01204 
01205 ********************************************************************************************/
01206 
01207 DocRect MouldPerspective::GetSourceRect()
01208 { 
01209     RECT Rect = Perspective.GetSourceBBox();
01210     return ConvRectToDocRect(Rect);
01211 }
01212 
01213 
01214 
01215 /*******************************************************************************************
01216 
01217 >   virtual BOOL MouldPerspective::OnClick( DocCoord Coord, 
01218                                             ClickType CType,
01219                                             ClickModifiers Mods,
01220                                             Spread* pSpread,
01221                                             NodeMould* pNodeMould)
01222 
01223     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01224     Created:    2/12/94
01225     Inputs:     Coord   = coordinate of mouse
01226                 CType   = the type of click (single, double, drag)
01227                 Mods    = the click modifiers
01228                 pSpread = a pointer to the spread the click occured over
01229     Returns     TRUE    if we processed the click
01230                 FALSE   if none of the vanishing points were under the click position
01231     Purpose:    Checks to see if any of the perspective vanishing points have been clicked
01232                 on. If not return FALSE
01233 
01234 ********************************************************************************************/
01235 
01236 BOOL MouldPerspective::OnClick( DocCoord PointerPos, 
01237                                 ClickType CType,
01238                                 ClickModifiers Mods,
01239                                 Spread* pSpread,
01240                                 NodeMould* pNodeMould)
01241 {
01242     BOOL Claimed=FALSE;
01243 
01244 #ifndef STANDALONE
01245 
01246     // we only handle the click if we can confirm that object blobs are being displayed.
01247     BlobManager* pBlobMgr = GetApplication()->GetBlobManager();
01248     if (pBlobMgr == NULL)
01249         return FALSE;
01250     if (!pBlobMgr->GetCurrentInterest().Object)
01251         return FALSE;
01252 
01253     PerspectiveClick WhatToDo = DetermineClickEffect(PointerPos,pSpread);
01254 
01255     switch (CType)
01256     {
01257         case CLICKTYPE_SINGLE:
01258             switch (WhatToDo)
01259             {
01260                 case PClick_EditVPoint0:
01261                 {
01262                     Claimed=TRUE;                   
01263                     OpDragOrigin* pOpDragOrigin = new OpDragOrigin;
01264                     if (pOpDragOrigin!=NULL)
01265                         pOpDragOrigin->DoDragVanishPoint(pSpread,PointerPos,Mods,pNodeMould,FALSE);
01266                 }
01267                 break;
01268 
01269                 case PClick_EditVPoint1:
01270                 {
01271                     Claimed=TRUE;
01272                     OpDragOrigin* pOpDragOrigin = new OpDragOrigin;
01273                     if (pOpDragOrigin!=NULL)
01274                         pOpDragOrigin->DoDragVanishPoint(pSpread,PointerPos,Mods,pNodeMould,TRUE);
01275                 }
01276                 break;
01277                 default: break;
01278             }                   
01279             break;
01280 
01281         case CLICKTYPE_DOUBLE:
01282             break;
01283         case CLICKTYPE_DRAG:
01284             break;
01285         default: break;
01286     }                   
01287 
01288 #endif
01289 
01290     return Claimed;
01291 }
01292 
01293 /*******************************************************************************************
01294 
01295 >   virtual BOOL MouldPerspective::OnMouseMove( DocCoord Coord, 
01296                                                 Spread* pSpread,
01297                                                 ClickModifiers Mods
01298                                                 INT32* ctype,
01299                                                 INT32* msgres)
01300 
01301     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01302     Created:    2/12/94
01303     Inputs:     Coord   = coordinate of mouse
01304                 Mods    = the click modifiers
01305                 pSpread = a pointer to the spread the click occured over
01306     Returns:    ctype   = the tool cursor type to use over this point
01307                 msgres  = the message resource type to use over this point
01308     Purpose:
01309 
01310 ********************************************************************************************/
01311 
01312 BOOL MouldPerspective::OnMouseMove(DocCoord Coord, 
01313                                 Spread* pSpread,
01314                                 ClickModifiers Mods,
01315                                 INT32* ctype,
01316                                 INT32* msgres)
01317 {
01318 #ifndef STANDALONE
01319 
01320     ERROR2IF(ctype==NULL,FALSE,"MouldPerspective::OnMouseMove passed a null cursor type ptr");
01321     ERROR2IF(msgres==NULL,FALSE,"MouldPerspective::OnMouseMove passed a null msg res ptr");
01322 
01323     PerspectiveClick Click = DetermineClickEffect(Coord, pSpread);
01324     switch (Click)
01325     {
01326         case PClick_EditVPoint0:
01327         case PClick_EditVPoint1:
01328             *ctype = 2;
01329             *msgres = 2;
01330             return TRUE;
01331             break;
01332         default: break;
01333     }
01334 
01335 #endif
01336 
01337     return FALSE;
01338 }
01339 
01340 /**************************************************************************************************************
01341 
01342 >   PerspectiveClick MouldPerspective::DetermineClickEffect(DocCoord PointerPos, Spread* pSpread)
01343 
01344     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01345     Created:    30/1/95
01346     Inputs:     PointerPos is the mouse position
01347                 pSpread is a pointer to the spread containing the mouse position
01348     Outputs:    -
01349     Returns:    A click type, which defines what edit action should be taken.
01350     Purpose:    Used when single clicking. This routine determines what effect a click will have.
01351                 The perspective mould provides draggable vanishing point blobs so we need to check
01352                 whether someones trying to click and drag one of these.
01353 
01354 ***************************************************************************************************************/
01355 
01356 PerspectiveClick MouldPerspective::DetermineClickEffect(DocCoord PointerPos,Spread* pSpread)
01357 {
01358 #if !defined(EXCLUDE_FROM_RALPH)
01359     DocRect Rect;
01360     DocCoord v0,v1;
01361 
01362     GetVanishingPoints(v0,v1);
01363 
01364     if (v0.x!=PER_UNDEFINED)
01365     {
01366         Rect=CalcBlobClipRect(v0);
01367         if (Rect.ContainsCoord(PointerPos))
01368             return PClick_EditVPoint0;
01369     }
01370 
01371     if (v1.x!=PER_UNDEFINED)
01372     {
01373         Rect=CalcBlobClipRect(v1);
01374         if (Rect.ContainsCoord(PointerPos))
01375             return PClick_EditVPoint1;
01376     }
01377 
01378 #endif
01379     return PClick_DoNothing;    
01380 }
01381 
01382 
01383 
01384 
01385 /********************************************************************************************
01386 
01387 >   virtual void MouldPerspective::Transform(Path* const pNewGeom,
01388                                              DocRect* const pRect,
01389                                              TransformBase& Trans )
01390 
01391     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01392     Created:    2/12/94
01393     Inputs:     pNewGeom = a new mould shape to use.
01394                 Trans    = The transform to be applied.
01395     Purpose:    As the actual perspective mould shape is a nodepath inside the mould parent
01396                 which this mouldperspecitive object is associated with, the path is passed
01397                 into this function whenever the mould parent receives a transform call.
01398                 The path has already been transformed so all we need to do here is update
01399                 the low level perspective bits.
01400 
01401 ********************************************************************************************/
01402 
01403 void MouldPerspective::Transform(Path* const pNewGeom,
01404                                  DocRect* const pRect,
01405                                  TransformBase& Trans )
01406 {
01407     // transform the blob origins, vanishing points etc
01408     Define(pNewGeom,pRect);
01409 }
01410 
01411 
01412 
01413 /***********************************************************************************************
01414 
01415 >   virtual ChangeCode MouldPerspective::RecordContext(UndoableOperation* pOp)
01416 
01417     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01418     Created:    16/01/95
01419     Inputs:     pOp = pointer to a running undoable operation
01420     Outputs:    -
01421     Purpose:    Record our context on the undo. In this overridden function we simply create
01422                 an action to perform the undo/redo of our perspective shape.
01423 
01424 ***********************************************************************************************/
01425 
01426 ChangeCode MouldPerspective::RecordContext(UndoableOperation* pOp)
01427 {
01428     if (pOp!=NULL)
01429     {
01430         RecordPerspectiveAction* PerAction;
01431         ActionCode Act;
01432 
01433         // call the actions static init function to get the action going.
01434         Act = RecordPerspectiveAction::Init(pOp, pOp->GetUndoActionList(), this, (Action**)(&PerAction));
01435 
01436         if (Act == AC_FAIL)
01437             return CC_FAIL;
01438         if (Act == AC_NORECORD)
01439             return CC_NORECORD;
01440     }
01441     return CC_OK;
01442 }
01443 
01444 
01445 /***********************************************************************************************
01446 
01447 >   virtual ChangeCode MouldPerspective::RecordBlobs(UndoableOperation* pOp, Spread* pSpread)
01448 
01449     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01450     Created:    26/01/95
01451     Inputs:     pOp = pointer to a running undoable operation
01452     Outputs:    -
01453     Purpose:    Record our blobs on the undo. In this overridden function we simply store
01454                 our blob rectangles so that they will redraw correctly during undo and
01455                 redo.
01456 
01457 ***********************************************************************************************/
01458 
01459 ChangeCode MouldPerspective::RecordBlobs(UndoableOperation* pOp, Spread* pSpread)
01460 {
01461 #ifndef STANDALONE
01462 
01463     if (pOp!=NULL)
01464     {
01465         ActionCode  Act;
01466         DocCoord    v0,v1;
01467         DocRect     Rect;
01468 
01469         GetVanishingPoints(v0,v1);
01470 
01471         if (v0.x!=PER_UNDEFINED)
01472         {
01473             Rect=CalcBlobClipRect(v0);
01474             Act=InvalidateRectAction::DoRecord(pOp,Rect,pSpread);
01475 
01476             if (Act == AC_FAIL) 
01477                 return CC_FAIL;
01478             if (Act == AC_NORECORD)
01479                 return CC_NORECORD;
01480         }
01481 
01482         if (v1.x!=PER_UNDEFINED)
01483         {
01484             Rect=CalcBlobClipRect(v1);
01485             Act=InvalidateRectAction::DoRecord(pOp,Rect,pSpread);
01486 
01487             if (Act == AC_FAIL)
01488                 return CC_FAIL;
01489             if (Act == AC_NORECORD)
01490                 return CC_NORECORD;
01491         }
01492 
01493     }
01494 #endif
01495 
01496     return CC_OK;
01497 }
01498 
01499 
01500 
01501 
01502 
01503 /********************************************************************************************
01504 
01505     RecordPerspectiveAction::RecordPerspectiveAction()
01506 
01507     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01508     Created:    16/01/95
01509     Purpose:    Constructor for the action to undo Perspective modification
01510 
01511 ********************************************************************************************/
01512 
01513 RecordPerspectiveAction::RecordPerspectiveAction()
01514 {
01515     pCPerspective=NULL;
01516 }
01517 
01518 
01519 /********************************************************************************************
01520 
01521     RecordPerspectiveAction::~RecordPerspectiveAction()
01522 
01523     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01524     Created:    16/01/95
01525     Purpose:    Destructor for the action to undo Perspective modification
01526 
01527 ********************************************************************************************/
01528 
01529 RecordPerspectiveAction::~RecordPerspectiveAction()
01530 {
01531 }
01532 
01533 
01534 /********************************************************************************************
01535 
01536 >   ActionCode RecordPerspectiveAction::Init(Operation* pOp,
01537                                              ActionList* pActionList,
01538                                              Action** NewAction)
01539 
01540     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01541     Created:    16/01/95
01542     Inputs:     pOp         = a pointer to the operation to which this action belongs
01543                 pActionList = is the action list to which this action should be added
01544 
01545     Outputs:    NewAction   = a pointer to a pointer to an action, allowing the function to 
01546                               return a pointer to the created action.
01547     Returns:    ActionCode, 
01548                     = AC_OK         if the action was created correctly
01549                     = AC_NORECORD   if no memory to undo/redo but go ahead anyway without undo
01550                     = AC_FAIL       stop the operation
01551 
01552     Purpose:    This is the function which creates an instance of this action. If there is
01553                 no room in the undo buffer (which is determined by the base class Init 
01554                 function called within) the function will either return AC_NORECORD which
01555                 means the operation can continue, but no undo information needs to be stored,
01556                 or AC_OK which means the operation should continue AND record undo information.
01557                 If the function returns AC_FAIL, there was not enough memory to record the 
01558                 undo information, and the user has decided not to continue with the operation.
01559     Errors:     -
01560     SeeAlso:    Action::Init()
01561 
01562 ********************************************************************************************/
01563 
01564 ActionCode RecordPerspectiveAction::Init(Operation* pOp,
01565                                          ActionList* pActionList,
01566                                          MouldPerspective* pPerspective,
01567                                          Action** NewAction)
01568 {
01569     ActionCode Ac = AC_FAIL;
01570     if (pPerspective!=NULL)
01571     {
01572         UINT32 ActSize = sizeof(RecordPerspectiveAction);
01573         Ac = Action::Init( pOp, pActionList, ActSize, CC_RUNTIME_CLASS(RecordPerspectiveAction), NewAction);
01574         if (Ac==AC_OK)
01575         {
01576             RecordPerspectiveAction* pAct = ((RecordPerspectiveAction*)*NewAction);
01577             if (pAct)
01578             {
01579                 pAct->pCPerspective = pPerspective;
01580                 pPerspective->Perspective.CopyShape(pAct->RecordArray);
01581             }
01582         }
01583     }
01584     return Ac;
01585 }
01586 
01587 /********************************************************************************************
01588 
01589 >   ActionCode RecordPerspectiveAction::Execute()
01590 
01591     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01592     Created:    16/01/95
01593     Inputs:     -
01594     Outputs:    -
01595     Returns:    ActionCode, 
01596                     = AC_OK         if the action was created correctly
01597                     = AC_NORECORD   if no memory to undo/redo but go ahead anyway without undo
01598                     = AC_FAIL       stop the operation
01599     Purpose:    This is the virtual function that is called when the action is executed
01600                 by the Undo/Redo system. This is the function that actually undoes the Perspective
01601                 change action by swapping the current internal definition of the Perspective with
01602                 the contexts of itself.
01603     Errors:     -
01604     SeeAlso:    -
01605 
01606 ********************************************************************************************/
01607 
01608 ActionCode RecordPerspectiveAction::Execute()
01609 {
01610     // try to create a redo record
01611     RecordPerspectiveAction* EnvAction;
01612     ActionCode Act;
01613     Act = RecordPerspectiveAction::Init(pOperation, pOppositeActLst, pCPerspective, (Action**)(&EnvAction));
01614     
01615     // for undo, simply copy 'this' record over the shape.
01616     // No No , we dont need to check for AC_OK, hands off! we've done all that in the
01617     // init function which tries to record the current state of the Perspective
01618     if (pCPerspective)
01619         pCPerspective->BuildShape(RecordArray,NULL);
01620 
01621     return Act;
01622 }
01623 
01624 
01625 
01626 
01627 
01628 
01629 /********************************************************************************************
01630 
01631 >   static BOOL PerspectiveShapes::Rectangular()
01632 
01633     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01634     Created:    11/12/94
01635     Inputs:     pPath = a pointer to an empty path (should be initialised but empty)
01636     Outputs:    a unit rectangular perspective, ready to be scaled to fit the selection.
01637     Returns:    TRUE if the rectangular perspective manifold has been created
01638                 FALSE if no memory to create the perspective.
01639     Purpose:    Creates a rectangular perspective. The perspective manifold is defined on a
01640                 millipoint square coordinate system. ie its outer coorinates are
01641                 (0,0), (72000,72000).
01642                 So to scale the perspective perform Coord = (ScaleFactor * Coord / 72000)
01643 
01644 ********************************************************************************************/
01645 
01646 BOOL PerspectiveShapes::Rectangular(Path* pPath)
01647 {
01648     ERROR2IF(pPath==NULL,FALSE,"NULL path pointer passed to PerspectiveShapes::Rectangular()");
01649 
01650     DocCoord point[PER_NUMCOORDS];
01651 
01652     point[0].x = 0; 
01653     point[0].y = 0;
01654     point[1].x = 0;
01655     point[1].y = 72000;
01656     point[2].x = 72000;
01657     point[2].y = 72000;
01658     point[3].x = 72000;
01659     point[3].y = 0;
01660 
01661     return MakeShape(pPath,point);
01662 }
01663 
01664 
01665 BOOL PerspectiveShapes::LeftWall(Path* pPath)
01666 {
01667     ERROR2IF(pPath==NULL,FALSE,"NULL path pointer passed to PerspectiveShapes::LeftWall()");
01668 
01669     DocCoord point[PER_NUMCOORDS];
01670 
01671     point[0].x = 0; 
01672     point[0].y = 0;
01673     point[1].x = 0;
01674     point[1].y = 72000;
01675     point[2].x = 72000;
01676     point[2].y = 45000;
01677     point[3].x = 72000;
01678     point[3].y = 27000;
01679 
01680     return MakeShape(pPath,point);
01681 }
01682 
01683 
01684 BOOL PerspectiveShapes::RightWall(Path* pPath)
01685 {
01686     ERROR2IF(pPath==NULL,FALSE,"NULL path pointer passed to PerspectiveShapes::RightWall()");
01687 
01688     DocCoord point[PER_NUMCOORDS];
01689 
01690     point[0].x = 0; 
01691     point[0].y = 27000;
01692     point[1].x = 0;
01693     point[1].y = 45000;
01694     point[2].x = 72000;
01695     point[2].y = 72000;
01696     point[3].x = 72000;
01697     point[3].y = 0;
01698 
01699     return MakeShape(pPath,point);
01700 }
01701 
01702 
01703 BOOL PerspectiveShapes::Floor(Path* pPath)
01704 {
01705     ERROR2IF(pPath==NULL,FALSE,"NULL path pointer passed to PerspectiveShapes::Floor()");
01706 
01707     DocCoord point[PER_NUMCOORDS];
01708 
01709     point[0].x = 0; 
01710     point[0].y = 0;
01711     point[1].x = 27000;
01712     point[1].y = 72000;
01713     point[2].x = 45000;
01714     point[2].y = 72000;
01715     point[3].x = 72000;
01716     point[3].y = 0;
01717 
01718     return MakeShape(pPath,point);
01719 }
01720 
01721 
01722 BOOL PerspectiveShapes::Ceiling(Path* pPath)
01723 {
01724     ERROR2IF(pPath==NULL,FALSE,"NULL path pointer passed to PerspectiveShapes::Ceiling()");
01725 
01726     DocCoord point[PER_NUMCOORDS];
01727 
01728     point[0].x = 27000; 
01729     point[0].y = 0;
01730     point[1].x = 0;
01731     point[1].y = 72000;
01732     point[2].x = 72000;
01733     point[2].y = 72000;
01734     point[3].x = 45000;
01735     point[3].y = 0;
01736 
01737     return MakeShape(pPath,point);
01738 }
01739 
01740 
01741 
01742 BOOL PerspectiveShapes::MakeShape(Path* pPath, DocCoord* point)
01743 {
01744     PathFlags flags;
01745     flags.IsSelected = FALSE;
01746 
01747     // Build a perspective manifold
01748     BOOL ok = (pPath->AddMoveTo(point[0],&flags));
01749     if (!ok) return FALSE;
01750 
01751     ok = (pPath->AddLineTo(point[1],&flags));
01752     if (!ok) return FALSE;
01753 
01754     ok = (pPath->AddLineTo(point[2],&flags));
01755     if (!ok) return FALSE;
01756 
01757     ok = (pPath->AddLineTo(point[3],&flags));
01758     if (!ok) return FALSE;
01759 
01760     ok = (pPath->AddLineTo(point[0],&flags));
01761     if (!ok) return FALSE;
01762 
01763     ok = (pPath->CloseSubPath());
01764 
01765     return (ok);
01766 }
01767 
01768 
01769 
01770 
01771 
01773 //
01774 // GPerspec.cpp
01775 //
01777 
01778 GPerspective::GPerspective()
01779 {
01780     // Initialise the perspective with sensible values
01781     P0.x = 0; P0.y = 0;
01782     P1.x = 0; P1.y = 1;
01783     P2.x = 1; P2.y = 1;
01784     P3.x = 1; P3.y = 0;
01785 
01786     ScaleView();
01787     CalcViewConsts();
01788 }
01789 
01790 
01791 BOOL GPerspective::Redefine( POINT *P )
01792 {
01793     // Read the four point perspective
01794     P0.x = P[0].x ; P0.y = P[0].y ;
01795     P1.x = P[1].x ; P1.y = P[1].y ;
01796     P2.x = P[2].x ; P2.y = P[2].y ;
01797     P3.x = P[3].x ; P3.y = P[3].y ;
01798 
01799     // Calc the bounds of the perspective
01800     CalcViewBBox();
01801     if (Width<1024) Width=1024;
01802     if (Depth<1024) Depth=1024;
01803 
01804     ScaleView();
01805     CalcViewConsts();
01806 
01807     return TRUE;
01808 }
01809 
01810 
01811 void GPerspective::CalcViewBBox()
01812 {
01813     MinX = MaxX = P0.x ;
01814     MinY = MaxY = P0.y ;
01815     MinX = min( MinX, INT32(P1.x) ) ; MaxX = max( MaxX, INT32(P1.x) ) ;
01816     MinY = min( MinY, INT32(P1.y) ) ; MaxY = max( MaxY, INT32(P1.y) ) ;
01817     MinX = min( MinX, INT32(P2.x) ) ; MaxX = max( MaxX, INT32(P2.x) ) ;
01818     MinY = min( MinY, INT32(P2.y) ) ; MaxY = max( MaxY, INT32(P2.y) ) ;
01819     MinX = min( MinX, INT32(P3.x) ) ; MaxX = max( MaxX, INT32(P3.x) ) ;
01820     MinY = min( MinY, INT32(P3.y) ) ; MaxY = max( MaxY, INT32(P3.y) ) ;
01821     Width = MaxX-MinX ;
01822     Depth = MaxY-MinY ;
01823 }
01824 
01825 
01826 void GPerspective::ScaleView()
01827 {
01828     // normalise the view
01829     V0.x = (double)(P0.x-MinX)/Width ;
01830     V0.y = (double)(P0.y-MinY)/Depth ;
01831     V1.x = (double)(P1.x-MinX)/Width ;
01832     V1.y = (double)(P1.y-MinY)/Depth ;
01833     V2.x = (double)(P2.x-MinX)/Width ;
01834     V2.y = (double)(P2.y-MinY)/Depth ;
01835     V3.x = (double)(P3.x-MinX)/Width ;
01836     V3.y = (double)(P3.y-MinY)/Depth ;
01837 }
01838 
01839 
01840 void GPerspective::CalcViewConsts()
01841 {
01842     // Calculate the view constants
01843     double N, D ;
01844     D = (V1.y-V0.y)*(V2.x-V3.x) - (V1.x-V0.x)*(V2.y-V3.y) ;
01845 
01846     if (( I0flag = (fabs(D) >= EPSILON) ))
01847     {
01848         N = (V3.y-V0.y)*(V2.x-V3.x) - (V3.x-V0.x)*(V2.y-V3.y) ;
01849         I0pos = (N<0.0) ^ (D<0.0) ;
01850         I0.x = V0.x+(V1.x-V0.x)*N/D ;
01851         I0.y = V0.y+(V1.y-V0.y)*N/D ;
01852         A.x = (V0.x-I0.x)*(V1.x-I0.x) ;
01853         A.y = (V0.y-I0.y)*(V1.y-I0.y) ;
01854         B.x = (V3.x-I0.x)*(V2.x-I0.x) ;
01855         B.y = (V3.y-I0.y)*(V2.y-I0.y) ;
01856     }       
01857 
01858     D = (V0.y-V3.y)*(V1.x-V2.x) - (V0.x-V3.x)*(V1.y-V2.y) ;
01859 
01860     if (( I1flag = (fabs(D) >= EPSILON) ))
01861     {
01862         N = (V2.y-V3.y)*(V1.x-V2.x) - (V2.x-V3.x)*(V1.y-V2.y) ;
01863         I1pos = (N<0.0) ^ (D<0.0) ;
01864         I1.x = V3.x+(V0.x-V3.x)*N/D ;
01865         I1.y = V3.y+(V0.y-V3.y)*N/D ;
01866     }       
01867 }
01868 
01869 
01870 
01871 void GPerspective::CopyShape(POINT* P)
01872 {
01873     P[0].x = P0.x ; P[0].y = P0.y ; 
01874     P[1].x = P1.x ; P[1].y = P1.y ;
01875     P[2].x = P2.x ; P[2].y = P2.y ;
01876     P[3].x = P3.x ; P[3].y = P3.y ;
01877 }
01878 
01879 
01880 
01881 BOOL GPerspective::Valid()
01882 {
01883     BOOL F = (
01884         ((V0.x==V1.x) && (V0.y==V1.y)) ||
01885         ((V1.x==V2.x) && (V1.y==V2.y)) ||
01886         ((V2.x==V3.x) && (V2.y==V3.y)) ||
01887         ((V3.x==V0.x) && (V3.y==V0.y))
01888         );
01889 
01890     if (F) return FALSE;
01891 
01892     F  =  (V1.x-V0.x)*(V3.y-V0.y) > (V1.y-V0.y)*(V3.x-V0.x) ;
01893     if ( F != ((V2.x-V1.x)*(V0.y-V1.y) > (V2.y-V1.y)*(V0.x-V1.x)) ) return FALSE ;
01894     if ( F != ((V3.x-V2.x)*(V1.y-V2.y) > (V3.y-V2.y)*(V1.x-V2.x)) ) return FALSE ;
01895     if ( F != ((V0.x-V3.x)*(V2.y-V3.y) > (V0.y-V3.y)*(V2.x-V3.x)) ) return FALSE ;
01896     return TRUE ;
01897 }
01898 
01899 
01900 BOOL GPerspective::WhichVanishingPoint(POINT v, BOOL& b)
01901 {
01902     if (I0flag)
01903     {
01904         POINT a;
01905         InverseScale(I0,a);
01906         if (a.x==v.x && a.y==v.y)
01907         {
01908             b=FALSE;
01909             return TRUE;
01910         }
01911     }
01912 
01913     if (I1flag)
01914     {
01915         POINT a;
01916         InverseScale(I1,a);
01917         if (a.x==v.x && a.y==v.y)
01918         {
01919             b=TRUE;
01920             return TRUE;
01921         }
01922     }
01923     return FALSE;
01924 }
01925 
01926 
01927 INT32 GPerspective::GetVPointState()
01928 {
01929     INT32 num=0;
01930     if (I0pos) num+=1;
01931     if (I1pos) num+=2;
01932     return num;
01933 }
01934 
01935 void GPerspective::VanishingPoints( POINT& a, POINT& b )
01936 {
01937     if ( I0flag )
01938         InverseScale( I0, a ) ;
01939     else
01940         a.x = a.y = 0x80000000 ;
01941     if ( I1flag )
01942         InverseScale( I1, b ) ;
01943     else
01944         b.x = b.y = 0x80000000 ;
01945 }
01946 
01947 
01948 
01949 void GPerspective::DragVanishingPoints( POINT& NewI, BOOL Flag, LPPOINT P )
01950 {
01951     DPOINT I ;
01952     Scale( NewI, I ) ;
01953     if ( !Flag )
01954         if ( !I0pos )
01955         {
01956             Intersect( I, V0, V1, V2, P[1] ) ;
01957             Intersect( I, V3, V1, V2, P[2] ) ;
01958         }
01959         else
01960         {
01961             Intersect( I, V1, V0, V3, P[0] ) ;
01962             Intersect( I, V2, V0, V3, P[3] ) ;
01963         }
01964     else
01965         if ( I1pos )
01966         {
01967             Intersect( I, V0, V3, V2, P[3] ) ;
01968             Intersect( I, V1, V3, V2, P[2] ) ;
01969         }
01970         else
01971         {
01972             Intersect( I, V3, V0, V1, P[0] ) ;
01973             Intersect( I, V2, V0, V1, P[1] ) ;
01974         }
01975 }
01976 
01978 
01979 
01980 BOOL GPerspective::FitPath (
01981                         CONST POINT* IPoints,
01982                         CONST BYTE*  ITypes,
01983                         DWORD ILength,
01984                         LPPOINT pOPoints,
01985                         LPBYTE  pOTypes,
01986                         DWORD pOLength,
01987                         BOOL Close
01988                     )
01989 {
01990     OPoints = pOPoints ;
01991     OTypes  = pOTypes  ;
01992     OLength = pOLength ;
01993 
01994     DPOINT     C2, C4 ;
01995     DPOINT P0, P2, P4, P6 ;
01996     DPOINT T0, T2, T4, T6 ;
01997     while ( ILength )
01998     {
01999         switch ( *ITypes & PT_MOVETO )
02000         {
02001         case PT_MOVETO :
02002         case PT_LINETO :
02003             --ILength ;
02004             ScaleSrc( *IPoints++, P0 ) ;
02005             Transform( P0, T0 ) ;
02006             if ( !GenOp( *ITypes++, T0 ) ) return -1 ;
02007             break ;
02008         case PT_BEZIERTO :
02009             ILength -= 3 ;
02010             ScaleSrc( *IPoints++, C2 ) ;
02011             ScaleSrc( *IPoints++, C4 ) ;
02012             ScaleSrc( *IPoints++, P6 ) ;
02013             P2.x = (8*P0.x+12*C2.x+ 6*C4.x+  P6.x)/27 ;
02014             P2.y = (8*P0.y+12*C2.y+ 6*C4.y+  P6.y)/27 ;
02015             P4.x = (  P0.x+ 6*C2.x+12*C4.x+8*P6.x)/27 ;
02016             P4.y = (  P0.y+ 6*C2.y+12*C4.y+8*P6.y)/27 ;
02017             Transform( P2, T2 ) ;
02018             Transform( P4, T4 ) ;
02019             Transform( P6, T6 ) ;
02020             if ( !GenCurve( C2, C4, P0, P2, P4, P6, T0, T2, T4, T6 ) ) return -1 ;
02021             P0.x = P6.x ; P0.y = P6.y ;
02022             T0.x = T6.x ; T0.y = T6.y ;
02023             ITypes += 3 ;
02024             *(OTypes-1) = *(ITypes-1) ;
02025             break ;
02026         default :
02027             return -1 ;
02028         }
02029     }
02030     if ( ILength )
02031         return -1 ;
02032     return pOLength-OLength ;
02033 }
02034 
02035 
02036 
02037 void GPerspective::Transform( DPOINT a, DPOINT& b )
02038 {
02039     DPOINT p, q ;
02040     p.x = V0.x ;
02041     p.y = V0.y ;
02042     q.x = V3.x ;
02043     q.y = V3.y ;
02044     if ( notequal(a.y,0) )
02045         if ( I0flag )
02046         {
02047             if ( notequal(V0.x,V1.x) )
02048                 p.x = I0.x+A.x/(a.y*(V0.x-V1.x)+V1.x-I0.x) ;
02049             if ( notequal(V0.y,V1.y) )
02050                 p.y = I0.y+A.y/(a.y*(V0.y-V1.y)+V1.y-I0.y) ;
02051             if ( notequal(V3.x,V2.x) )
02052                 q.x = I0.x+B.x/(a.y*(V3.x-V2.x)+V2.x-I0.x) ;
02053             if ( notequal(V3.y,V2.y) )
02054                 q.y = I0.y+B.y/(a.y*(V3.y-V2.y)+V2.y-I0.y) ;
02055         }
02056         else
02057         {
02058             p.x = V0.x+a.y*(V1.x-V0.x) ;
02059             p.y = V0.y+a.y*(V1.y-V0.y) ;
02060             q.x = V3.x+a.y*(V2.x-V3.x) ;
02061             q.y = V3.y+a.y*(V2.y-V3.y) ;
02062         }
02063     b.x = p.x ;
02064     b.y = p.y ;
02065     if ( notequal(a.x,0) )
02066         if ( I1flag )
02067         {
02068             if ( notequal(p.x,q.x) )
02069                 b.x = I1.x+(p.x-I1.x)*(q.x-I1.x)/(a.x*(p.x-q.x)+q.x-I1.x) ;
02070             if ( notequal(p.y,q.y) )
02071                 b.y = I1.y+(p.y-I1.y)*(q.y-I1.y)/(a.x*(p.y-q.y)+q.y-I1.y) ;
02072         }
02073         else
02074         {
02075             b.x = p.x+a.x*(q.x-p.x) ;
02076             b.y = p.y+a.x*(q.y-p.y) ;
02077         }
02078 }
02079 
02080 
02081 void GPerspective::Intersect( DPOINT I, DPOINT P0, DPOINT P1, DPOINT P2, POINT& O )
02082 {
02083     double N, D ;
02084     DPOINT T ;
02085     N = (P1.y-P0.y)*(P2.x-P1.x) - (P1.x-P0.x)*(P2.y-P1.y) ;
02086     D = ( I.y-P0.y)*(P2.x-P1.x) - ( I.x-P0.x)*(P2.y-P1.y) ;
02087     T.x = P0.x+(I.x-P0.x)*N/D ;
02088     T.y = P0.y+(I.y-P0.y)*N/D ;
02089     InverseScale( T, O ) ;
02090 }
02091 

Generated on Sat Nov 10 03:45:44 2007 for Camelot by  doxygen 1.4.4