moldenv.cpp

Go to the documentation of this file.
00001 // $Id: moldenv.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 // Envelope shape implementation
00099 
00100 /*
00101 */
00102 
00103 #include "camtypes.h"
00104 #include "moldenv.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 "osrndrgn.h"
00109 //#include "docview.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00110 //#include "ops.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00111 //#include "trans2d.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00112 #include "pathproc.h"
00113 //#include "mike.h"
00114 #include "genv.h"
00115 
00116 #include <math.h>
00117 
00118 DECLARE_SOURCE("$Revision: 1282 $");
00119 
00120 CC_IMPLEMENT_DYNAMIC(MouldEnvelopeBase,MouldGeometry)
00121 CC_IMPLEMENT_DYNAMIC(MouldEnvelope,MouldEnvelopeBase)
00122 CC_IMPLEMENT_DYNAMIC(MouldEnvelope2x2,MouldEnvelopeBase)
00123 CC_IMPLEMENT_DYNCREATE(RecordEnvelopeAction,Action)
00124 
00125 // Declare smart memory handling in Debug builds
00126 #define new CAM_DEBUG_NEW
00127 
00128 
00129 /*******************************************************************************************
00130 
00131 >   MouldEnvelopeBase::MouldEnvelopeBase() 
00132 
00133     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00134     Created:    2/12/94
00135     Inputs:     
00136     Purpose:    EnvelopeBase mould constructor
00137 
00138 ********************************************************************************************/
00139 
00140 MouldEnvelopeBase::MouldEnvelopeBase()
00141 {
00142     BlobState = 0;
00143     pEnvelope = NULL;
00144 }
00145 
00146 
00147 /*******************************************************************************************
00148 
00149 >   MouldEnvelopeBase::~MouldEnvelopeBase()
00150 
00151     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00152     Created:    2/12/94
00153     Inputs:     
00154     Purpose:    EnvelopeBase mould destructor
00155 
00156 ********************************************************************************************/
00157 
00158 MouldEnvelopeBase::~MouldEnvelopeBase()
00159 {
00160     if (pEnvelope!=NULL)
00161     {
00162         delete pEnvelope;
00163         pEnvelope=NULL;
00164     }
00165 }
00166 
00167 
00168 /*******************************************************************************************
00169 
00170 >   BOOL MouldEnvelopeBase::ValidMouldingPath(INT32 ncoords, INT32 nelements, Path* const pPath, UINT32& errorID)
00171 
00172     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00173     Created:    2/12/94
00174     Inputs:     
00175     Purpose:    Check to see whether a mould path is suitable for use
00176 
00177 ********************************************************************************************/
00178 
00179 BOOL MouldEnvelopeBase::ValidMouldingPath(INT32 ncoords, INT32 nelements, Path* const pPath, UINT32& errorID)
00180 {
00181     // now we need a more complex check
00182     DocCoord* Coords = pPath->GetCoordArray();
00183     PathVerb* Verbs = pPath->GetVerbArray();
00184 
00185     // we need the first element to be a move to
00186     if (Verbs[0]!=PT_MOVETO)
00187     {
00188         errorID = _R(IDE_ENV_BADELEMENT);
00189         return FALSE;
00190     }
00191 
00192     // followed by either lineto or bezierto els
00193     INT32 nume=0;
00194     PathVerb V;
00195 
00196     for (INT32 i=1; i<ncoords; i++)
00197     {
00198         V = Verbs[i] & (~PT_CLOSEFIGURE);
00199         switch (V)
00200         {
00201             case PT_LINETO:
00202                 nume+=1;
00203                 break;
00204             case PT_BEZIERTO:
00205                 nume+=1; i+=2;
00206                 break;
00207             default:
00208                 errorID = _R(IDE_ENV_NUMCOORDERR);
00209                 return FALSE;
00210                 break;
00211         }
00212         if (nume>nelements)
00213         {
00214             errorID = _R(IDE_ENV_NUMCOORDERR);
00215             return FALSE;
00216         }
00217     }
00218 
00219     // And the last coordinate must close the loop
00220     if (Coords[0]!=Coords[ncoords-1])
00221     {
00222         errorID = _R(IDE_ENV_NOTCLOSED);
00223         return FALSE;
00224     }
00225 
00226     return TRUE;
00227 }
00228 
00229 
00230 /*******************************************************************************************
00231 
00232     static BOOL MouldEnvelopeBase::WillBeValid(INT32 ncoords, POINT* P)
00233 
00234     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00235     Created:    12/12/94
00236     Inputs:     ncoords = the number of coordinates in P
00237                 P a pointer to a POINT array of coordinates
00238     Returns:    TRUE if the point set is valid
00239     Purpose:    Check whether the point array suited for use as a manifold
00240 
00241 ********************************************************************************************/
00242 
00243 BOOL MouldEnvelopeBase::WillBeValid(INT32 ncoords, POINT* P)
00244 {
00245     INT32 MinX, MaxX, MinY, MaxY, Width, Depth ;
00246 
00247     MinX = MaxX = P[0].x ;
00248     MinY = MaxY = P[0].y ;
00249 
00250     for (INT32 i=1; i<ncoords; i++)
00251     {
00252         MinX = min( MinX, INT32(P[i].x) );
00253         MaxX = max( MaxX, INT32(P[i].x) );
00254         MinY = min( MinY, INT32(P[i].y) );
00255         MaxY = max( MaxY, INT32(P[i].y) );
00256     }
00257 
00258     Width = MaxX-MinX ;
00259     Depth = MaxY-MinY ;
00260 
00261     if (Width==0 || Depth==0)
00262         return FALSE;
00263 
00264     return TRUE;
00265 }
00266 
00267 
00268 /*******************************************************************************************
00269 
00270 >   BOOL MouldEnvelopeBase::Define(Path* const pPath, DocRect* const pOrigBBox, INT32 ncoords)
00271 
00272     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00273     Created:    2/12/94
00274     Inputs:     pPath     = the path to use for enveloping
00275                 pOrigBBox = a pointer to the bounding box of the objects to be enveloped
00276                           = NULL then the old bounding box will be assumed.
00277     returns:    TRUE    - then SetUp has succeded
00278                 FALSE   - then setup has failed to initialise itself
00279     Purpose:    This function sets the low level envelope state ready for calls to various
00280                 envelope path generation functions. It serves simply as a way of informing
00281                 the low level enveloper of the shape of the current envelope
00282 
00283 ********************************************************************************************/
00284 
00285 BOOL MouldEnvelopeBase::Define(Path* const pPath, DocRect* const pOrigBBox, INT32 ncoords)
00286 {
00287     ERROR2IF(pPath==NULL,FALSE,"MouldEnvelopeBase::Define() called with NULL path");
00288     ERROR2IF(ncoords>ENV_MAXCOORDS, FALSE, "MouldEnvelopeBase::Define() - ncoords too large");
00289     INT32 numc = pPath->GetNumCoords();
00290 
00291     POINT* pPoints = (POINT*)pPath->GetCoordArray();
00292     POINT  qPoints[ENV_MAXCOORDS+1];
00293     POINT* rPoints = pPoints;
00294 
00295     if (numc<(ncoords+1))
00296     {
00297         if (!ConvertShape(ncoords,qPoints,pPath,numc))
00298             return FALSE;
00299         rPoints = qPoints;
00300     }
00301 
00302     return BuildShape(rPoints,pOrigBBox);
00303 }
00304 
00305 
00306 /*******************************************************************************************
00307 
00308 >   RECT MouldEnvelopeBase::BuildShape(POINT* pPoints, DocRect* const pOrigBBox) 
00309 
00310     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00311     Created:    11/01/95
00312     Inputs:     pPoints     = a pointer to a array of INT32 coordinates
00313                 pOrigBBox   = a pointer to the bounding box of the objects to be enveloped
00314                             = NULL then the old bounding box will be assumed.
00315     Returns:    TRUE    - then BuildShape has succeded
00316                 FALSE   - then BuildShape has failed to create the mould shape
00317     Purpose:    
00318 
00319 ********************************************************************************************/
00320 
00321 BOOL MouldEnvelopeBase::BuildShape(POINT* pPoints, DocRect* const pOrigBBox)
00322 {
00323     ERROR2IF(pPoints==NULL,FALSE,"MouldEnvelopeBase::BuildShape() called with NULL point list");
00324     ERROR3IF(pEnvelope==NULL,"MouldEnvelopeBase::BuildShape() - pEnvelope is NULL!");
00325 
00326     if (pOrigBBox!=NULL)
00327     {
00328         if (pOrigBBox->IsEmpty())
00329             return FALSE;
00330         if (!pOrigBBox->IsValid())
00331             return FALSE;
00332     }
00333 
00334     RECT ObjRect = BuildRectangle(pOrigBBox);
00335     return pEnvelope->Define(pPoints,&ObjRect,MouldThreshold);
00336 }
00337 
00338 
00339 /*******************************************************************************************
00340 
00341 >   RECT MouldEnvelopeBase::BuildRectangle(DocRect* const pOrigBBox) 
00342 
00343     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00344     Created:    11/01/95
00345     Inputs:     pOrigBBox = a pointer to the bounding box of the objects to be enveloped
00346                           = NULL then the old bounding box will be assumed.
00347     Returns:    a RECT structure.           
00348     Purpose:    Build a RECT structure to pass to the low level envelope code. 
00349 
00350 ********************************************************************************************/
00351 
00352 RECT MouldEnvelopeBase::BuildRectangle(DocRect* const pOrigBBox)
00353 {
00354     ERROR3IF(pEnvelope==NULL,"MouldEnvelopeBase::BuildRectangle() - pEnvelope is NULL!");
00355     RECT ObjRect;
00356 
00357     if (pOrigBBox!=NULL)
00358     {
00359         // set up the low level envelope data.
00360         ObjRect.left    = pOrigBBox->lo.x;
00361         ObjRect.bottom  = pOrigBBox->lo.y;
00362         ObjRect.right   = pOrigBBox->hi.x;
00363         ObjRect.top     = pOrigBBox->hi.y;
00364     }
00365     else
00366         ObjRect = pEnvelope->GetSourceBBox();
00367 
00368     return ObjRect;
00369 }
00370 
00371 
00372 
00373 
00374 /*******************************************************************************************
00375 
00376 >   virtual void MouldEnvelopeBase::ToggleControlBlobs(Spread* pSpread)
00377 
00378     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00379     Created:    2/12/94
00380     Inputs:     pSpread = pointer to a spread to render into
00381     Purpose:    
00382 
00383 ********************************************************************************************/
00384 
00385 void MouldEnvelopeBase::ToggleControlBlobs(Spread* pSpread)
00386 {
00387     // if we're in a suspended state do nothing!
00388     if (BlobState>1) return;
00389     // toggle the grid state.
00390     BlobState ^= 1;
00391 
00392     if (pSpread!=NULL)
00393         RenderGrid(pSpread);
00394 }
00395 
00396 /*******************************************************************************************
00397 
00398 >   virtual void MouldEnvelopeBase::Enable/DisableControlBlobs()
00399 
00400     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00401     Created:    2/12/94
00402     Inputs:     -
00403     Purpose:    Used when an envelope is undergoing a drag, we disable normal blob rendering
00404                 
00405 ********************************************************************************************/
00406 
00407 void MouldEnvelopeBase::EnableControlBlobs()
00408 {
00409     if (BlobState>1) BlobState--;
00410 }
00411 
00412 void MouldEnvelopeBase::DisableControlBlobs()
00413 {
00414     if (BlobState>0) BlobState++;
00415 }
00416 
00417 
00418 /*******************************************************************************************
00419 
00420 >   virtual void MouldEnvelopeBase::RenderControlBlobs(RenderRegion* pRegion)
00421 
00422     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00423     Created:    2/12/94
00424     Inputs:     pRegion = pointer to a region to render into
00425     Purpose:    Draw on the envelope grid points on if they are supposed to be shown.
00426 
00427 ********************************************************************************************/
00428 
00429 void MouldEnvelopeBase::RenderControlBlobs(RenderRegion* pRegion)
00430 {
00431     ERROR3IF(pRegion==NULL,"MouldEnvelopeBase::RenderControlBlobs passed a NULL region");
00432     if (pRegion==NULL) return;
00433     if (BlobState!=1) return;
00434 
00435     RenderGrid(pRegion);
00436 }
00437 
00438 
00439 /*******************************************************************************************
00440 
00441 >   virtual void MouldEnvelopeBase::RenderDragBlobs(RenderRegion* pRegion)
00442 
00443     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00444     Created:    2/12/94
00445     Inputs:     pRegion = pointer to a region to render into
00446     Purpose:    Draw on the envelope grid points on if they are supposed to be shown.
00447 
00448 ********************************************************************************************/
00449 
00450 void MouldEnvelopeBase::RenderDragBlobs(Spread* pSpread)
00451 {
00452     ERROR3IF(pSpread==NULL,"MouldEnvelopeBase::RenderDragBlobs passed a NULL spread");
00453     if (pSpread==NULL) return;
00454     if (BlobState<1) return;
00455 
00456     RenderGrid(pSpread);
00457 }
00458 
00459 
00460 /*******************************************************************************************
00461 
00462 >   void MouldEnvelopeBase::RenderGrid(Spread* pSpread)
00463 
00464     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00465     Created:    2/12/94
00466     Inputs:     pSpread = pointer to a spread to render into
00467     Purpose:    Draw on the envelope grid points on if they are supposed to be shown.
00468 
00469 ********************************************************************************************/
00470 
00471 void MouldEnvelopeBase::RenderGrid(Spread* pSpread)
00472 {
00473     ERROR3IF(pEnvelope==NULL,"MouldEnvelopeBase::RenderGrid - no envelope pointer");
00474     DocRect Rect = pEnvelope->GetBoundingRect();
00475     RenderRegion* pRegion = DocView::RenderOnTop( &Rect, pSpread, ClippedEOR );
00476     while ( pRegion )
00477     {
00478         RenderGrid(pRegion);
00479         pRegion = DocView::GetNextOnTop(NULL);
00480     }   
00481 }
00482 
00483 
00484 /*******************************************************************************************
00485 
00486 >   void MouldEnvelopeBase::RenderGrid(RenderRegion* pRegion)
00487 
00488     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00489     Created:    2/12/94
00490     Inputs:     pRegion = pointer to a region to render into
00491     Purpose:    Draw on the envelope grid points on if they are supposed to be shown.
00492 
00493 ********************************************************************************************/
00494 
00495 void MouldEnvelopeBase::RenderGrid(RenderRegion* pRegion)
00496 {
00497     ERROR3IF(pRegion==NULL,"MouldEnvelopeBase::RenderControlBlobs() passed a NULL region");
00498     if (pRegion==NULL) return;
00499 
00500     // get the base class to render
00501     MouldGeometry::RenderControlBlobs(pRegion);
00502     // set the colour of our outline
00503     pRegion->SetLineWidth(0);                               // Means single-pixel lines
00504     pRegion->SetLineColour(COLOUR_XOREDIT);
00505     pRegion->SetFillColour(COLOUR_XOREDIT);
00506     // now render the grid
00507     RenderGridPoints(pRegion);
00508 }
00509 
00510 
00511 /*******************************************************************************************
00512 
00513 >   void MouldEnvelopeBase::RenderGridPoints(RenderRegion* pRegion)
00514 
00515     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00516     Created:    04/01/95
00517     Inputs:     pRegion = pointer to a region to render into
00518     Purpose:    Draw on the envelope grid points on if they are supposed to be shown.
00519 
00520 ********************************************************************************************/
00521 
00522 void MouldEnvelopeBase::RenderGridPoints(RenderRegion* pRegion)
00523 {
00524     // We need to scan through the origin bounding rectangle, calculating
00525     // an MxN rectangle of points, transforming them all and rendering them to the region
00526 
00527     ERROR3IF(pEnvelope==NULL,"MouldEnvelopeBase::RenderGridPoints() - pEnvelope is NULL!");
00528 
00529     INT32 p0 = 8;
00530     INT32 p1 = 4*p0;
00531     INT32 a,b,x,y;
00532     POINT sU,dU;
00533     DocCoord pU;
00534     RECT Bounds = pEnvelope->GetSourceBBox();
00535     INT32 dX = Bounds.right - Bounds.left;
00536     INT32 dY = Bounds.top - Bounds.bottom;
00537 
00538     for (a=1; a<p0; a++)
00539     {
00540         x = Bounds.left + a*dX/p0;
00541         y = Bounds.bottom + a*dY/p0;
00542 
00543         for (b=1; b<p1; b++)
00544         {
00545             if (b % (p1/p0))
00546             {
00547                 sU.x = Bounds.left + b*dX/p1;
00548                 sU.y = y;
00549                 pEnvelope->FitPoint(sU,dU);
00550                 pU.x = dU.x;
00551                 pU.y = dU.y;
00552                 pRegion->DrawPixel(pU);
00553             }
00554 
00555             sU.x = x;
00556             sU.y = Bounds.bottom + b*dY/p1;
00557             pEnvelope->FitPoint(sU,dU);
00558             pU.x = dU.x;
00559             pU.y = dU.y;
00560             pRegion->DrawPixel(pU);
00561         }
00562     }
00563 }
00564 
00565 
00566 
00567 /********************************************************************************************
00568 
00569 >   DocRect MouldEnvelopeBase::GetSourceRect()
00570 
00571     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00572     Created:    17/01/95
00573     Inputs:     
00574     Returns:    a doc rect.
00575     Purpose:    Return the current definition of the mould envelope source rectangle.
00576 
00577 ********************************************************************************************/
00578 
00579 DocRect MouldEnvelopeBase::GetSourceRect()
00580 { 
00581     ERROR3IF(pEnvelope==NULL,"MouldEnvelopeBase::GetSourceRect() - pEnvelope is NULL!");
00582 
00583     RECT Rect = pEnvelope->GetSourceBBox();
00584     return ConvRectToDocRect(Rect);
00585 }
00586 
00587 
00588 /*******************************************************************************************
00589 
00590 >   virtual BOOL MouldEnvelopeBase::MouldPathToPath(Path* pSourcePath, Path* pDestinPath)
00591 
00592     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00593     Created:    2/12/94
00594     Inputs:     pSourcePath = pointer to a path object to mould
00595                 pDestinPath = pointer to a path buffer to put the resulting moulded path in
00596                               this should be at least an initialise path.
00597     Outputs:    pDestinPath contains the moulded version of the path
00598     Returns:    TRUE    - if the mould was successfull
00599                 FALSE   - if no room to create the mould
00600 
00601     Purpose:    Using the defined envelope, this function takes the input path shape and
00602                 generates a moulded output path. The output path may contain data on entry
00603                 to this routine, the enveloped path will simply be added to the end of the
00604                 data already there. If the input path is closed, the output path will be
00605                 closed likewise.
00606 
00607 ********************************************************************************************/
00608 
00609 BOOL MouldEnvelopeBase::MouldPathToPath(Path* pSourcePath, Path* pDestinPath)
00610 {
00611     ERROR2IF(pSourcePath==NULL, FALSE, "MouldEnvelopeBase::MouldPathToPath() passed a NULL source pointer");
00612     ERROR2IF(pDestinPath==NULL, FALSE, "MouldEnvelopeBase::MouldPathToPath() passed a NULL destin pointer");
00613 
00614     // get the source path data length
00615     DWORD ilength = (DWORD)pSourcePath->GetNumCoords();
00616 
00617     // if there's no input path, then there's no output path, and all is well.
00618     if (ilength<1)
00619         return TRUE;
00620 
00621     INT32 freespace = ilength*4;
00622     INT32 maxspace = ilength*16;
00623     BOOL ok;
00624     INT32 added;
00625 
00626     Path TempPath;
00627     if (!TempPath.Initialise(freespace,24))
00628         return FALSE;
00629 
00630     do
00631     {
00632         // get the source object and destin object path data
00633         POINT* icoords = (POINT*)pSourcePath->GetCoordArray();
00634         BYTE*  iverbs  = (BYTE*)pSourcePath->GetVerbArray();
00635         POINT* ocoords = (POINT*)TempPath.GetCoordArray();
00636         BYTE*  overbs  = (BYTE*)TempPath.GetVerbArray();
00637 
00638         // try to create an enveloped path
00639         added = pEnvelope->FitPath(icoords,iverbs,ilength,ocoords,overbs,freespace,FALSE);
00640 
00641         if (added==-1)
00642         {
00643             freespace*=2;
00644             // create what we think will be enough space for the output path
00645             ok = TempPath.EnsureVolume(freespace);
00646             if (!ok) 
00647                 return FALSE;
00648         }
00649 
00650     } while ((added==-1) && freespace<=maxspace);
00651 
00652     // if we've failed to create the enveloped object then tidy up
00653     if (added<=1)
00654         return FALSE;
00655 
00656     // now lets set up the new flags array
00657     ok = TempPath.ExternalArraysReplaced(added);
00658     if (ok)
00659         TempPath.InitialiseFlags(0,added);
00660 
00661     if (ok)
00662     {
00663 /*
00664         // Ok check for rampant null elements in this path
00665         DocCoord* Coords;
00666         PathVerb* Verbs;
00667         PathFlags* Flags;
00668         PathVerb CurVerb;
00669         INT32 i,lmi;
00670         DocCoord lm;
00671 
00672         TempPath.GetPathArrays(&Verbs,&Coords,&Flags);
00673 
00674         for (i=0; i<added; i++)
00675         {
00676             CurVerb = Verbs[i] & ~PT_CLOSEFIGURE;
00677             if (CurVerb==PT_MOVETO)
00678             {
00679                 lm=Coords[i];
00680                 lmi=i;
00681             }
00682 
00683             if (CurVerb==PT_BEZIERTO)
00684             {
00685                 if (Verbs[i+2] & PT_CLOSEFIGURE)
00686                 {
00687                     DocCoord p0,p1,p2;
00688                     p0 = Coords[i];
00689                     p1 = Coords[i+1];
00690                     p2 = Coords[i+2];
00691                     if ((p0.x==p1.x) && (p1.x==p2.x) && (p2.x==lm.x) &&
00692                         (p0.y==p1.y) && (p1.y==p2.y) && (p2.y==lm.y) && 
00693                         (i-lmi)>1)
00694                     {
00695                         // We can delete this element!
00696                         Verbs[i-1] |= PT_CLOSEFIGURE;
00697                         if (TempPath.DeleteSection(i,3))
00698                         {
00699                             added-=3;
00700                             i-=3;
00701                         }
00702                         else
00703                             i=added;
00704                     }
00705                 }
00706                 i+=2;
00707             }
00708         }
00709 */
00710 
00711         ok = pDestinPath->CloneFrom(TempPath);
00712     }
00713     return ok;
00714 }
00715 
00716 
00717 /*******************************************************************************************
00718 
00719 >   virtual BOOL MouldEnvelopeBase::MouldPoint(DocCoord p, DocCoord& q)
00720 
00721     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00722     Created:    2/12/94
00723     Inputs:     p = the coordinate to be transformed
00724     Outputs:    q = the transformed version of the coordinate
00725     Returns:    TRUE if the point has been transformed
00726                 FALSE if q==p
00727     Purpose:    Using the defined envelope, this function takes the input coordinate
00728                 and calculates its transformed version.
00729 
00730 ********************************************************************************************/
00731 
00732 BOOL MouldEnvelopeBase::MouldPoint(DocCoord p,DocCoord& q)
00733 {
00734     // I aught to check that the point as contained within the source rectangle
00735     // bbox and do something about it if not. But what to do?
00736 
00737     RECT rect = pEnvelope->GetSourceBBox();
00738 
00739     if  ((p.x<rect.left) || (p.x>rect.right) ||
00740         (p.y<rect.bottom) || (p.y>rect.top))
00741     {
00742         q=p;
00743         return FALSE;
00744     }
00745 
00746     POINT r,s;
00747 
00748     r.x = p.x;
00749     r.y = p.y;
00750 
00751     pEnvelope->FitPoint(r,s);
00752 
00753     q.x = s.x;
00754     q.y = s.y;
00755 
00756     return TRUE;
00757 }
00758 
00759 
00760 /*******************************************************************************************
00761 
00762 >   virtual BOOL MouldEnvelopeBase::MouldBitmapToTile(Blit* pSourceBlit, Blit* pDestinBlit)
00763 
00764     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00765     Created:    2/12/94
00766     Inputs:     pSourceBlit = pointer to a bitmap to envelope
00767                 pDestinBlit = pointer to an output tile to mould into
00768     Outputs:    pDestinBlit = enveloped version of the bitmap
00769     Returns:    TRUE    - if the mould was successfull
00770                 FALSE   - if no room to create the mould
00771     Purpose:    Create an enveloped version of a bitmap, ready to be rendered to a device
00772 
00773 ********************************************************************************************/
00774 
00775 BOOL MouldEnvelopeBase::MouldBitmapToTile(KernelBitmap* pSourceBlit, KernelBitmap* pDestinBlit)
00776 {
00777     // currently not implemented
00778     return FALSE;
00779 }
00780 
00781 
00782 /*******************************************************************************************
00783 
00784 >   BOOL MouldEnvelopeBase::ConvertShape(INT32 ncoords, POINT* dPoints, Path* const pPath, const INT32 numcoords)
00785 
00786     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00787     Created:    2/12/94
00788     Inputs:     ncoords   = number of output coordinates in this mould
00789                 dPoints   = array of points to hold the calculated coordinates
00790                 pPath     = the path to use for enveloping
00791                 numcoords = the number of coordinaties in pPath
00792     Outputs:    dPoints   = the destination point set.
00793     returns:    TRUE    - then the shape has been converted.
00794                 FALSE   - then this convert has failed.
00795     Purpose:    Converts a path into a shape suitable for use as a mould. This function can
00796                 be used in two contexts, dependent on the value of dPoints. If this is NULL
00797                 on entry, an output path will be calculated but not stored in the output
00798                 buffer (obvoiusly). You could then use the return value of the function for
00799                 input path validation ie if the function returns false to this type of call
00800                 you can assume the input path is not valid ie cannot be converted. You could
00801                 assume this of course whatever dPoints is set to but it gives you the ability
00802                 to first try to convert the path and then allocate space for the output if
00803                 you so wish.
00804 
00805 ********************************************************************************************/
00806 
00807 BOOL MouldEnvelopeBase::ConvertShape(INT32 ncoords, POINT* dPoints, Path* const pPath, const INT32 numcoords)
00808 {
00809     POINT* sPoints = (POINT*)pPath->GetCoordArray();
00810     PathVerb* sVerbs = pPath->GetVerbArray();
00811 
00812     INT32 out=(ncoords+1);
00813     INT32 i=0; 
00814     INT32 j=0;
00815 
00816     while ((i<numcoords) && (out>0))
00817     {
00818         switch ((sVerbs[i] & ~PT_CLOSEFIGURE))
00819         {
00820             case PT_MOVETO:
00821             case PT_BEZIERTO:
00822                 out--;
00823                 if (out>=0)
00824                 {
00825                     if (dPoints)
00826                     {
00827                         dPoints[j].x=sPoints[i].x;
00828                         dPoints[j].y=sPoints[i].y;
00829                     }
00830                     i++; j++;
00831                 }
00832                 break;
00833 
00834             case PT_LINETO:
00835                 out-=3;
00836                 if (out>=0)
00837                 {
00838                     if (dPoints)
00839                     {
00840                         dPoints[j+0].x = (2*sPoints[i-1].x + sPoints[i].x)/3;
00841                         dPoints[j+0].y = (2*sPoints[i-1].y + sPoints[i].y)/3;
00842                         dPoints[j+1].x = (sPoints[i-1].x + 2*sPoints[i].x)/3;
00843                         dPoints[j+1].y = (sPoints[i-1].y + 2*sPoints[i].y)/3;
00844                         dPoints[j+2].x = sPoints[i].x;
00845                         dPoints[j+2].y = sPoints[i].y;
00846                     }
00847                     i++; j+=3; 
00848                 }
00849                 break;
00850             default:
00851                 return FALSE;
00852                 break;
00853         }
00854     }
00855     return (out==0);
00856 }
00857 
00858 /*******************************************************************************************
00859 
00860 >   virtual void MouldEnvelopeBase::MouldPathRender(Path* pPath, Spread* pSpread)
00861 
00862     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00863     Created:    2/12/94
00864     Inputs:     pPath   = pointer to a path to envelope
00865                 pRegion = pointer to a region to render into
00866     Purpose:
00867 
00868 ********************************************************************************************/
00869 
00870 void MouldEnvelopeBase::MouldPathRender(Path* pPath, Spread* pSpread)
00871 {
00872 }
00873 
00874 
00875 
00876 
00877 /*******************************************************************************************
00878 
00879 >   virtual void MouldEnvelopeBase::MouldBitmapRender(KernelBitmap* pBlit,
00880                                                       DocCoord* pParallel,
00881                                                       RenderRegion* pRegion)
00882 
00883     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00884     Created:    2/12/94
00885     Inputs:     pBlit       = pointer to a kernel bitmap
00886                 pParallel   = pointer to a four point parallelogram
00887                 pRegion     = pointer to a region to render into
00888     Purpose:
00889 
00890 ********************************************************************************************/
00891 
00892 void MouldEnvelopeBase::MouldBitmapRender(KernelBitmap* pBlit, 
00893                                           DocCoord* Parallel,
00894                                           RenderRegion* pRegion)
00895 {
00896     pRegion->SaveContext();
00897 
00898     // No lines on the rectangle
00899     pRegion->SetLineColour(COLOUR_TRANS);
00900 
00901     pRegion->RestoreContext();
00902 
00903 }
00904 
00905 
00906 
00907 
00908 
00912 
00913 /*******************************************************************************************
00914 
00915 >   MouldEnvelope::MouldEnvelope() 
00916 
00917     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00918     Created:    2/12/94
00919     Inputs:     
00920     Purpose:    Envelope mould constructor
00921 
00922 ********************************************************************************************/
00923 
00924 MouldEnvelope::MouldEnvelope() : EnvNumCoords(ENV_NUMCOORDS)
00925 {
00926 }
00927 
00928 /*******************************************************************************************
00929 
00930 >   MouldEnvelope::~MouldEnvelope()
00931 
00932     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00933     Created:    2/12/94
00934     Inputs:     
00935     Purpose:    Envelope mould destructor
00936 
00937 ********************************************************************************************/
00938 
00939 MouldEnvelope::~MouldEnvelope()
00940 {
00941 }
00942 
00943 
00944 /*******************************************************************************************
00945 
00946 >   MouldEnvelope::Initialise()
00947 
00948     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00949     Created:    2/12/94
00950     Inputs:     
00951     Purpose:    Initialise a mould envelope to contain the correct geometry
00952 
00953 ********************************************************************************************/
00954 
00955 BOOL MouldEnvelope::Initialise()
00956 {
00957     ERROR3IF(MouldEnvelopeBase::pEnvelope!=NULL, "MouldEnvelope::Initialise() - pEnvelope not NULL!");
00958     GEnvelope* pGEnvelope = new GEnvelope;
00959     if (pGEnvelope==NULL)
00960         return FALSE;
00961     MouldEnvelopeBase::pEnvelope = pGEnvelope;
00962     return TRUE;
00963 }
00964 
00965 
00966 /*******************************************************************************************
00967 
00968 >   BOOL MouldEnvelope::Validate(Path* const pPath, UINT32& errorID)
00969 
00970     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00971     Created:    11/02/95
00972     Inputs:     pPath   = the path to use for enveloping
00973     Outputs:    errorID = an id of an error string reporting the problem when failed.
00974     Returns:    TRUE    - then the path can be used as an envelope
00975                 FALSE   - then the path is not suitable for use as an envelope
00976     Purpose:    This function checks whether the path given is suitabile for use as an
00977                 envelope manifold. Valid paths at present are any set of 5 path elements
00978                 starting with a moveto followed by line or bezier elements
00979 
00980 ********************************************************************************************/
00981 
00982 BOOL MouldEnvelope::Validate(Path* const pPath, UINT32& errorID)
00983 {
00984     // check for a reasonable number of coordinates
00985     INT32 numc=pPath->GetNumCoords();
00986     if ((numc<5) || numc>(EnvNumCoords+1)) 
00987     {
00988         errorID = _R(IDE_ENV_NUMCOORDERR);
00989         return FALSE;
00990     }
00991 
00992     if (!ValidMouldingPath(numc, 4, pPath, errorID))
00993         return FALSE;
00994 
00995     // Make sure there's no folds either
00996     POINT* p = (POINT*)pPath->GetCoordArray();
00997     if (!WillBeValid(p))
00998     {
00999         errorID = _R(IDE_ENV_NOWIDTHHEIGHT);
01000         return FALSE;
01001     }
01002 
01003     // Ok, now if necessary do a pseudo conversion
01004     if (numc<(EnvNumCoords+1))
01005     {
01006         if (!ConvertShape(EnvNumCoords,NULL,pPath,numc))
01007         {
01008             errorID = _R(IDE_ENV_NUMCOORDERR);
01009             return FALSE;
01010         }
01011     }
01012 
01013     // All is well, we should be able to use this shape
01014     return TRUE;
01015 }
01016 
01017 
01018 
01019 /*******************************************************************************************
01020 
01021     static BOOL MouldEnvelope::WillBeValid(POINT* P)
01022 
01023     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01024     Created:    12/12/94
01025     Inputs:     P a pointer to a POINT array of coordinates
01026     Returns:    TRUE if the point set is valid
01027     Purpose:    Check whether the point array suited for use as a manifold
01028 
01029 ********************************************************************************************/
01030 
01031 BOOL MouldEnvelope::WillBeValid(POINT* P)
01032 {
01033     return MouldEnvelopeBase::WillBeValid(ENV_NUMCOORDS, P);
01034 }
01035 
01036 
01037 /*******************************************************************************************
01038 
01039 >   BOOL MouldEnvelope::MakeValidFrom(Path **Out, Path *In, INT32 *CornersHint = 0)
01040 
01041     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
01042     Created:    24/05/95
01043     Inputs:     Out = variable to output the new Path in. In = path to create a valid one from.
01044     Returns:    whether it managed to create one or not
01045     Purpose:    creates a valid moulding path from an non-invalid path.
01046 
01047 ********************************************************************************************/
01048 
01049 BOOL MouldEnvelope::MakeValidFrom(Path **Out, Path *In, INT32 *CornersHint)
01050 {
01051     // get the bound rect of the path
01052     DocRect Bounds = In->GetBoundingRect();
01053     DocCoord TL(Bounds.lo.x, Bounds.hi.y);
01054     DocCoord BR(Bounds.hi.x, Bounds.lo.y);
01055 
01056     // run through the path finding points and work out which is closest to each corner
01057     INT32 Corners[4] = {-1, -1, -1, -1};
01058 
01059     INT32 BottomLeftDist=-1;
01060     INT32 BottomRightDist=-1;
01061     INT32 TopLeftDist=-1;
01062     INT32 TopRightDist=-1;
01063 
01064     // get the coord arrays
01065     DocCoord *Coords = In->GetCoordArray();
01066     PathVerb *Verbs = In->GetVerbArray();
01067     INT32 Entries = In->GetNumCoords();
01068     if(Entries < 2)
01069         return FALSE;
01070 
01071     INT32 Elements = 0;
01072 
01073     // run through
01074     for(INT32 Pass = 0; Pass < 4; Pass++)
01075     {
01076         INT32 dy, dx, dist;
01077         INT32 BezCount = 0;
01078         INT32 c;
01079 
01080         for(c = 0; c < Entries; c++)
01081         {
01082             BOOL LookAtThis = FALSE;
01083 
01084             switch(Verbs[c] & (~PT_CLOSEFIGURE))
01085             {
01086                 case PT_LINETO:
01087                     LookAtThis = TRUE;
01088                     break;
01089 
01090                 case PT_BEZIERTO:
01091                     BezCount++;
01092                     if(BezCount == 3)
01093                     {
01094                         BezCount = 0;
01095                         LookAtThis = TRUE;
01096                     }
01097                     break;
01098 
01099                 default:
01100                     break;
01101             }
01102                         #define CHECKAGAINST(var, vdist, near) {            \
01103                             dx = Coords[c].x - near.x;                      \
01104                             dy = Coords[c].y - near.y;                      \
01105                             dist = (INT32)sqrt((double)((dx * dx) + (dy * dy)));    \
01106                             BOOL notused = TRUE;                            \
01107                             for(INT32 l = 0; l < 4; l++)                        \
01108                             {                                               \
01109                                 if(Corners[l] == c)                         \
01110                                     notused = FALSE;                        \
01111                             }                                               \
01112                             if(notused && (var == -1 || dist < vdist))      \
01113                             {                                               \
01114                                 vdist = dist;                               \
01115                                 var = c;                                    \
01116                             }                                               \
01117                         }
01118 
01119             if(LookAtThis)
01120             {
01121                 switch(Pass)
01122                 {
01123                     case 0:
01124                         Elements++;     // only count elements on pass 0
01125                         CHECKAGAINST(Corners[0], BottomLeftDist, Bounds.lo)
01126                         break;
01127 
01128                     case 1:
01129                         CHECKAGAINST(Corners[1], TopLeftDist, TL)
01130                         break;
01131                 
01132                     case 2:
01133                         CHECKAGAINST(Corners[2], TopRightDist, Bounds.hi)
01134                         break;
01135 
01136                     case 3:
01137                         CHECKAGAINST(Corners[3], BottomRightDist, BR)
01138                         break;
01139 
01140                     default:
01141                         ERROR3("Unknown pass in MouldEnvelope::MakeValidFrom");
01142                         break;
01143                 }
01144             }
01145 
01146             if((Verbs[c] & (~PT_CLOSEFIGURE)) == PT_MOVETO && c != 0)
01147                 break;          // end at end of first sub path
01148         }
01149     }
01150 
01151     // got enough elements?
01152     if(Elements < 4)
01153     {
01154         return FALSE;
01155     }
01156 
01157     // got a hint about the corners?
01158     if(CornersHint != 0)
01159     {
01160         // yes - copy them in to the corners array we already have
01161         for(INT32 l = 0; l < 4; l++)
01162         {
01163             Corners[l] = CornersHint[l];
01164         }
01165     }
01166 
01167     // sort the points...
01168     INT32 s, l;
01169     for(s = 0; s < 3; s++)
01170     {
01171         for(l = 0; l < 3; l++)
01172         {
01173             if(Corners[l] > Corners[l+1])
01174             {
01175                 INT32 Temp = Corners[l];
01176                 Corners[l] = Corners[l+1];
01177                 Corners[l+1] = Temp;
01178             }
01179         }
01180     }
01181 
01182     // make a path object
01183     Path *OutputShape = new Path;
01184     if(OutputShape == 0 || !OutputShape->Initialise())
01185     {
01186         delete OutputShape;
01187         return FALSE;
01188     }
01189 
01190     OutputShape->FindStartOfPath();
01191 
01192     // go through appoximating beziers to each segment
01193     INT32 Side;
01194     for(Side = 0; Side < 4; Side++)
01195     {
01196         // work out which coords to start from
01197         INT32 StartCoord = Corners[Side];
01198         INT32 EndCoord;
01199         if(Side != 3)
01200             EndCoord = Corners[Side + 1];
01201         else
01202             EndCoord = Corners[0];
01203     
01204         ERROR2IF(StartCoord == EndCoord, FALSE, "Two corners the same in MakeValidFrom!");
01205 
01206         // generate a path
01207         INT32 CoordsNeeded = EndCoord - StartCoord;
01208         if(CoordsNeeded < 0)
01209             CoordsNeeded = 0 - CoordsNeeded;
01210 
01211         Path *SidePath = new Path;
01212         if(SidePath == 0 || !SidePath->Initialise(CoordsNeeded + 8, 12))
01213         {
01214             delete SidePath;
01215             delete OutputShape;
01216             return FALSE;
01217         }
01218 
01219         // OK, we've got a path with plenty of space in it - make the path of the side
01220         SidePath->FindStartOfPath();
01221     
01222         DocCoord StartPoint, EndPoint;
01223         
01224         // make a moveto... 
01225         if(!SidePath->InsertMoveTo(Coords[StartCoord]))
01226             return FALSE;
01227 
01228         StartPoint = Coords[StartCoord];
01229 
01230         // insert the coordinates
01231         BOOL WillWrap = FALSE;
01232 
01233         if(StartCoord > EndCoord)
01234             WillWrap = TRUE;
01235 
01236         INT32 At = StartCoord + 1;
01237         while((At <= EndCoord) || WillWrap)
01238         {
01239             // check for wrapping round
01240             if(WillWrap && (At >= Entries))
01241             {
01242                 At = 0;
01243                 WillWrap = FALSE;
01244             }
01245             else
01246             {
01247                 switch(Verbs[At] & (~PT_CLOSEFIGURE))
01248                 {
01249                     case PT_LINETO:
01250                         if(!SidePath->InsertLineTo(Coords[At]))
01251                             return FALSE;
01252 
01253                         At++;
01254                         break;
01255 
01256                     case PT_BEZIERTO:
01257                         if(!SidePath->InsertCurveTo(Coords[At], Coords[At+1], Coords[At+2]))
01258                             return FALSE;
01259 
01260                         At += 3;
01261                         break;
01262         
01263                     default:
01264                         At++;
01265                         break;
01266                 }
01267             }
01268 
01269         }
01270 
01271         EndPoint = Coords[EndCoord];
01272 
01273         // got it... now approximate a bezier to what we got.
01274 
01275         // find the path length
01276         ProcessLength PathLengthProcess(64);
01277         double fPathLength=0;
01278         if(!PathLengthProcess.PathLength(SidePath, &fPathLength))
01279             return FALSE;
01280 
01281         // find coords at 33% and 66% of the path length
01282         ProcessPathDistance PathDistanceProcess(64);
01283 
01284         DocCoord Point1;
01285         BOOL Found;
01286         if(!PathDistanceProcess.GetCoordAndTangent(&Point1, 0, &Found, fPathLength / 3, SidePath))
01287             return FALSE;
01288 
01289         DocCoord Point2;
01290         if(!PathDistanceProcess.GetCoordAndTangent(&Point2, 0, &Found, (fPathLength * 2) / 3, SidePath))
01291             return FALSE;
01292     
01293         // do some stuff which Mathematica emitted to find the control points for this segment
01294         DocCoord Control1, Control2;
01295 
01296         Control1.x = ((-5 * StartPoint.x) + (2 * EndPoint.x) + (18 * Point1.x) - (9 * Point2.x)) / 6;
01297         Control1.y = ((-5 * StartPoint.y) + (2 * EndPoint.y) + (18 * Point1.y) - (9 * Point2.y)) / 6;
01298         Control2.x = ((2 * StartPoint.x) - (5 * EndPoint.x) - (9 * Point1.x) + (18 * Point2.x)) / 6;
01299         Control2.y = ((2 * StartPoint.y) - (5 * EndPoint.y) - (9 * Point1.y) + (18 * Point2.y)) / 6;
01300     
01301         // if this is the first bit coord, we need a move to
01302         if(Side == 0)
01303         {
01304             if(!OutputShape->InsertMoveTo(StartPoint))
01305                 return FALSE;
01306         }
01307         
01308         // right then, add the nice curve...
01309         if(!OutputShape->InsertCurveTo(Control1, Control2, EndPoint))
01310             return FALSE;
01311     }
01312 
01313     // close the shape
01314     if(!OutputShape->CloseSubPath())
01315         return FALSE;
01316     
01317     // set the return pointer
01318     (*Out) = OutputShape;
01319 
01320     return TRUE;
01321 }
01322 
01323 
01324 /*******************************************************************************************
01325 
01326 >   BOOL MouldEnvelope::Define(Path* const pPath, DocRect* const pOrigBBox)
01327 
01328     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01329     Created:    2/12/94
01330     Inputs:     pPath     = the path to use for enveloping
01331                 pOrigBBox = a pointer to the bounding box of the objects to be enveloped
01332                           = NULL then the old bounding box will be assumed.
01333     returns:    TRUE    - then SetUp has succeded
01334                 FALSE   - then setup has failed to initialise itself
01335     Purpose:    This function sets the low level envelope state ready for calls to various
01336                 envelope path generation functions. It serves simply as a way of informing
01337                 the low level enveloper of the shape of the current envelope
01338 
01339 ********************************************************************************************/
01340 
01341 BOOL MouldEnvelope::Define(Path* const pPath, DocRect* const pOrigBBox)
01342 {
01343     ERROR2IF(pPath==NULL,FALSE,"MouldEnvelope::Define() called with NULL path");
01344     return MouldEnvelopeBase::Define(pPath,pOrigBBox,EnvNumCoords);
01345 }
01346 
01347 
01348 /*******************************************************************************************
01349 
01350 >   void MouldEnvelope::Transform(Path* const pPath, DocRect* const pRect, TransformBase& Trans )
01351 
01352     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01353     Created:    04/01/95
01354     Inputs:     pMould  = A pointer to the node mould object associated with this envelope
01355                 Trans   = A transformation object
01356     Purpose:    Make sure the envelope mould data is transformed correctly.
01357                 Note, all we need do here is redefine the low level envelope by calling
01358                 Define() again with the current NodePath shape. We are ofcourse assuming
01359                 that the child node path has already been transformed and so is correct.
01360                 This is the case for NodeMould.Transform() which calls this function.
01361                 It ensures all children are transformed first before it calls us passing
01362                 in the transformed path itself.
01363 
01364 ********************************************************************************************/
01365 
01366 void MouldEnvelope::Transform(Path* const pPath, DocRect* const pRect, TransformBase& Trans )
01367 {
01368     ERROR3IF(pPath==NULL,"MouldEnvelope::Transform() passed a NULL path shape");
01369     Define(pPath,pRect);    
01370 }
01371 
01372 
01373 
01374 
01375 /***********************************************************************************************
01376 
01377 >   virtual ChangeCode MouldEnvelope::RecordContext(UndoableOperation* pOp)
01378 
01379     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01380     Created:    16/01/95
01381     Inputs:     pOp = pointer to a running undoable operation
01382     Outputs:    -
01383     Purpose:    Record our context on the undo. In this overridden function we simply create
01384                 an action to perform the undo/redo of our envelope shape.
01385 
01386 ***********************************************************************************************/
01387 
01388 ChangeCode MouldEnvelope::RecordContext(UndoableOperation* pOp)
01389 {
01390     if (pOp!=NULL)
01391     {
01392         RecordEnvelopeAction* EnvAction;
01393         ActionCode Act;
01394 
01395         // call the actions static init function to get the action going.
01396         Act = RecordEnvelopeAction::Init(pOp, pOp->GetUndoActionList(), this, (Action**)(&EnvAction));
01397 
01398         if (Act == AC_FAIL)
01399             return CC_FAIL;
01400         if (Act == AC_NORECORD)
01401             return CC_NORECORD;
01402     }
01403     return CC_OK;
01404 }
01405 
01406 
01407 /********************************************************************************************
01408 
01409 >   virtual MouldGeometry* MouldEnvelope::MakeCopy()
01410 
01411     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01412     Created:    17/01/95
01413     Inputs:     -
01414     Outputs:    a pointer to a new mould envelope object.
01415                 NULL if unable to create the object.
01416     Purpose:    Make a copy of this mould envelope object and return it.
01417 
01418 ********************************************************************************************/
01419 
01420 MouldGeometry* MouldEnvelope::MakeCopy()
01421 {
01422     // create a new Geometry
01423     MouldEnvelope* pGeometry = new MouldEnvelope;
01424     if (pGeometry == NULL)
01425         return NULL;
01426 
01427     if (!pGeometry->Initialise())
01428     {
01429         delete pGeometry;
01430         return NULL;
01431     }
01432 
01433     if (!CopyContents(pGeometry))
01434     {
01435         delete pGeometry;
01436         return NULL;
01437     }
01438 
01439     return ((MouldGeometry*)pGeometry);
01440 }
01441 
01442 
01443 /********************************************************************************************
01444 
01445 >   BOOL MouldEnvelope::CopyContents(MouldEnvelope* pEnvelope)
01446 
01447     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01448     Created:    17/01/95
01449     Inputs:     pEnvelope = a pointer to a copy of a mould envelope.
01450     Outputs:    
01451     Returns:    TRUE if the data has been copied correctly
01452                 FALSE if failed
01453     Purpose:    Make a copy of this mouldenvelope class private data
01454 
01455 ********************************************************************************************/
01456 
01457 BOOL MouldEnvelope::CopyContents(MouldEnvelope* pCopyEnvelope)
01458 {
01459     ERROR3IF(pCopyEnvelope==NULL, "MouldEnvelope::CopyContents() passed a null pointer");
01460     // ask the base class to copy its bits first
01461     if (!MouldGeometry::CopyContents(pCopyEnvelope))
01462         return FALSE;
01463 
01464     // now lets copy data about ourselves
01465     POINT* TempArray = new POINT[EnvNumCoords];
01466     if (TempArray==NULL)
01467         return FALSE;
01468 
01469     RECT TempRect = pEnvelope->GetSourceBBox();
01470     DocRect Rect = ConvRectToDocRect(TempRect);
01471     pEnvelope->CopyShape(TempArray);
01472 
01473     // define this shape with the details
01474     BOOL ok = (pCopyEnvelope->BuildShape(TempArray, &Rect));
01475 
01476     delete [] TempArray;
01477     return ok;
01478 }
01479 
01482 
01483 
01484 /*******************************************************************************************
01485 
01486 >   MouldEnvelope2x2::MouldEnvelope2x2() 
01487 
01488     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01489     Created:    2/12/94
01490     Inputs:     
01491     Purpose:    Envelope mould constructor
01492 
01493 ********************************************************************************************/
01494 
01495 MouldEnvelope2x2::MouldEnvelope2x2() : EnvNumCoords(ENV_NUMCOORDS2X2)
01496 {
01497 }
01498 
01499 /*******************************************************************************************
01500 
01501 >   MouldEnvelope2x2::~MouldEnvelope2x2()
01502 
01503     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01504     Created:    2/12/94
01505     Inputs:     
01506     Purpose:    Envelope2x2 mould destructor
01507 
01508 ********************************************************************************************/
01509 
01510 MouldEnvelope2x2::~MouldEnvelope2x2()
01511 {
01512 }
01513 
01514 
01515 /*******************************************************************************************
01516 
01517 >   MouldEnvelope2x2::Initialise()
01518 
01519     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01520     Created:    2/12/94
01521     Inputs:     
01522     Purpose:    Initialise a mould envelope to contain the correct geometry
01523 
01524 ********************************************************************************************/
01525 
01526 BOOL MouldEnvelope2x2::Initialise()
01527 {
01528     ERROR3IF(MouldEnvelopeBase::pEnvelope!=NULL, "MouldEnvelope2x2::Initialise() - pEnvelope not NULL!");
01529     GEnvelope2x2* pGEnvelope = new GEnvelope2x2;
01530     if (pGEnvelope==NULL)
01531         return FALSE;
01532     MouldEnvelopeBase::pEnvelope = pGEnvelope;
01533     return TRUE;
01534 }
01535 
01536 
01537 /*******************************************************************************************
01538 
01539 >   BOOL MouldEnvelope2x2::Validate(Path* const pPath, UINT32& errorID)
01540 
01541     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01542     Created:    11/02/95
01543     Inputs:     pPath   = the path to use for enveloping
01544     Outputs:    errorID = an id of an error string reporting the problem when failed.
01545     Returns:    TRUE    - then the path can be used as an envelope
01546                 FALSE   - then the path is not suitable for use as an envelope
01547     Purpose:    This function checks whether the path given is suitabile for use as an
01548                 envelope manifold. Valid paths at present are any set of 5 path elements
01549                 starting with a moveto followed by line or bezier elements
01550 
01551 ********************************************************************************************/
01552 
01553 BOOL MouldEnvelope2x2::Validate(Path* const pPath, UINT32& errorID)
01554 {
01555     // check for a reasonable number of coordinates
01556     INT32 numc=pPath->GetNumCoords();
01557     if ((numc<5) || numc>(EnvNumCoords+1)) 
01558     {
01559         errorID = _R(IDE_ENV_NUMCOORDERR);
01560         return FALSE;
01561     }
01562 
01563     if (!ValidMouldingPath(numc, 8, pPath, errorID))
01564         return FALSE;
01565 
01566     // Make sure there's no folds either
01567     POINT* p = (POINT*)pPath->GetCoordArray();
01568     if (!WillBeValid(p))
01569     {
01570         errorID = _R(IDE_ENV_NOWIDTHHEIGHT);
01571         return FALSE;
01572     }
01573 
01574     // Ok, now if necessary do a pseudo conversion
01575     if (numc<(EnvNumCoords+1))
01576     {
01577         if (!ConvertShape(EnvNumCoords,NULL,pPath,numc))
01578         {
01579             errorID = _R(IDE_ENV_NUMCOORDERR);
01580             return FALSE;
01581         }
01582     }
01583 
01584     // All is well
01585     return TRUE;
01586 }
01587 
01588 
01589 
01590 /*******************************************************************************************
01591 
01592     static BOOL MouldEnvelope2x2::WillBeValid(POINT* P)
01593 
01594     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01595     Created:    12/12/94
01596     Inputs:     P a pointer to a POINT array of coordinates
01597     Returns:    TRUE if the point set is valid
01598     Purpose:    Check whether the point array suited for use as a manifold
01599 
01600 ********************************************************************************************/
01601 
01602 BOOL MouldEnvelope2x2::WillBeValid(POINT* P)
01603 {
01604     return MouldEnvelopeBase::WillBeValid(ENV_NUMCOORDS2X2, P);
01605 }
01606 
01607 
01608 /*******************************************************************************************
01609 
01610 >   BOOL MouldEnvelope2x2::MakeValidFrom(Path **Out, Path *In, INT32 *CornersHint = 0)
01611 
01612     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01613     Created:    24/05/95
01614     Inputs:     Out = variable to output the new Path in. In = path to create a valid one from.
01615     Returns:    whether it managed to create one or not
01616     Purpose:    creates a valid moulding path from an non-invalid path.
01617 
01618 ********************************************************************************************/
01619 
01620 BOOL MouldEnvelope2x2::MakeValidFrom(Path **Out, Path *In, INT32 *CornersHint)
01621 {
01622     return FALSE;
01623 }
01624 
01625 
01626 /*******************************************************************************************
01627 
01628 >   BOOL MouldEnvelope2x2::Define(Path* const pPath, DocRect* const pOrigBBox)
01629 
01630     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01631     Created:    2/12/94
01632     Inputs:     pPath     = the path to use for enveloping
01633                 pOrigBBox = a pointer to the bounding box of the objects to be enveloped
01634                           = NULL then the old bounding box will be assumed.
01635     returns:    TRUE    - then SetUp has succeded
01636                 FALSE   - then setup has failed to initialise itself
01637     Purpose:    This function sets the low level envelope state ready for calls to various
01638                 envelope path generation functions. It serves simply as a way of informing
01639                 the low level enveloper of the shape of the current envelope
01640 
01641 ********************************************************************************************/
01642 
01643 BOOL MouldEnvelope2x2::Define(Path* const pPath, DocRect* const pOrigBBox)
01644 {
01645     ERROR2IF(pPath==NULL,FALSE,"MouldEnvelope2x2::Define() called with NULL path");
01646     return MouldEnvelopeBase::Define(pPath,pOrigBBox,EnvNumCoords);
01647 }
01648 
01649 /*******************************************************************************************
01650 
01651 >   void MouldEnvelope2x2::Transform(Path* const pPath, DocRect* const pRect, TransformBase& Trans )
01652 
01653     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01654     Created:    04/01/95
01655     Inputs:     pMould  = A pointer to the node mould object associated with this envelope
01656                 Trans   = A transformation object
01657     Purpose:    Make sure the envelope mould data is transformed correctly.
01658                 Note, all we need do here is redefine the low level envelope by calling
01659                 Define() again with the current NodePath shape. We are ofcourse assuming
01660                 that the child node path has already been transformed and so is correct.
01661                 This is the case for NodeMould.Transform() which calls this function.
01662                 It ensures all children are transformed first before it calls us passing
01663                 in the transformed path itself.
01664 
01665 ********************************************************************************************/
01666 
01667 void MouldEnvelope2x2::Transform(Path* const pPath, DocRect* const pRect, TransformBase& Trans )
01668 {
01669     ERROR3IF(pPath==NULL,"MouldEnvelope2x2::Transform() passed a NULL path shape");
01670     Define(pPath,pRect);    
01671 }
01672 
01673 
01674 
01675 
01676 /***********************************************************************************************
01677 
01678 >   virtual ChangeCode MouldEnvelope2x2::RecordContext(UndoableOperation* pOp)
01679 
01680     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01681     Created:    16/01/95
01682     Inputs:     pOp = pointer to a running undoable operation
01683     Outputs:    -
01684     Purpose:    Record our context on the undo. In this overridden function we simply create
01685                 an action to perform the undo/redo of our envelope shape.
01686 
01687 ***********************************************************************************************/
01688 
01689 ChangeCode MouldEnvelope2x2::RecordContext(UndoableOperation* pOp)
01690 {
01691     if (pOp!=NULL)
01692     {
01693         RecordEnvelopeAction* EnvAction;
01694         ActionCode Act;
01695 
01696         // call the actions static init function to get the action going.
01697         Act = RecordEnvelopeAction::Init(pOp, pOp->GetUndoActionList(), this, (Action**)(&EnvAction));
01698 
01699         if (Act == AC_FAIL)
01700             return CC_FAIL;
01701         if (Act == AC_NORECORD)
01702             return CC_NORECORD;
01703     }
01704     return CC_OK;
01705 }
01706 
01707 
01708 /********************************************************************************************
01709 
01710 >   virtual MouldGeometry* MouldEnvelope2x2::MakeCopy()
01711 
01712     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01713     Created:    17/01/95
01714     Inputs:     -
01715     Outputs:    a pointer to a new mould envelope object.
01716                 NULL if unable to create the object.
01717     Purpose:    Make a copy of this mould envelope object and return it.
01718 
01719 ********************************************************************************************/
01720 
01721 MouldGeometry* MouldEnvelope2x2::MakeCopy()
01722 {
01723     // create a new Geometry
01724     MouldEnvelope2x2* pGeometry = new MouldEnvelope2x2;
01725     if (pGeometry == NULL)
01726         return NULL;
01727 
01728     if (!pGeometry->Initialise())
01729     {
01730         delete pGeometry;
01731         return NULL;
01732     }
01733 
01734     if (!CopyContents(pGeometry))
01735     {
01736         delete pGeometry;
01737         return NULL;
01738     }
01739 
01740     return ((MouldGeometry*)pGeometry);
01741 }
01742 
01743 
01744 /********************************************************************************************
01745 
01746 >   BOOL MouldEnvelope2x2::CopyContents(MouldEnvelope2x2* pEnvelope)
01747 
01748     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01749     Created:    17/01/95
01750     Inputs:     pEnvelope = a pointer to a copy of a mould envelope.
01751     Outputs:    
01752     Returns:    TRUE if the data has been copied correctly
01753                 FALSE if failed
01754     Purpose:    Make a copy of this mouldenvelope class private data
01755 
01756 ********************************************************************************************/
01757 
01758 BOOL MouldEnvelope2x2::CopyContents(MouldEnvelope2x2* pCopyEnvelope)
01759 {
01760     ERROR3IF(pCopyEnvelope==NULL, "MouldEnvelope::CopyContents() passed a null pointer");
01761     // ask the base class to copy its bits first
01762     if (!MouldGeometry::CopyContents(pCopyEnvelope))
01763         return FALSE;
01764 
01765     // now lets copy data about ourselves
01766     POINT* TempArray = new POINT[EnvNumCoords];
01767     if (TempArray==NULL)
01768         return FALSE;
01769 
01770     RECT TempRect = pEnvelope->GetSourceBBox();
01771     DocRect Rect = ConvRectToDocRect(TempRect);
01772     pEnvelope->CopyShape(TempArray);
01773 
01774     // define this shape with the details
01775     BOOL ok = (pCopyEnvelope->BuildShape(TempArray, &Rect));
01776 
01777     delete [] TempArray;
01778     return ok;
01779 }
01780 
01783 
01784 /********************************************************************************************
01785 
01786     RecordEnvelopeAction::RecordEnvelopeAction()
01787 
01788     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01789     Created:    16/01/95
01790     Purpose:    Constructor for the action to undo envelope modification
01791 
01792 ********************************************************************************************/
01793 
01794 RecordEnvelopeAction::RecordEnvelopeAction()
01795 {
01796     pCEnvelope=NULL;
01797 }
01798 
01799 
01800 /********************************************************************************************
01801 
01802     RecordEnvelopeAction::~RecordEnvelopeAction()
01803 
01804     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01805     Created:    16/01/95
01806     Purpose:    Destructor for the action to undo envelope modification
01807 
01808 ********************************************************************************************/
01809 
01810 RecordEnvelopeAction::~RecordEnvelopeAction()
01811 {
01812 }
01813 
01814 
01815 /********************************************************************************************
01816 
01817 >   ActionCode RecordEnvelopeAction::Init(  Operation* pOp,
01818                                             ActionList* pActionList,
01819                                             Action** NewAction)
01820 
01821     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01822     Created:    16/01/95
01823     Inputs:     pOp         = a pointer to the operation to which this action belongs
01824                 pActionList = is the action list to which this action should be added
01825 
01826     Outputs:    NewAction   = a pointer to a pointer to an action, allowing the function to 
01827                               return a pointer to the created action.
01828     Returns:    ActionCode, 
01829                     = AC_OK         if the action was created correctly
01830                     = AC_NORECORD   if no memory to undo/redo but go ahead anyway without undo
01831                     = AC_FAIL       stop the operation
01832 
01833     Purpose:    This is the function which creates an instance of this action. If there is
01834                 no room in the undo buffer (which is determined by the base class Init 
01835                 function called within) the function will either return AC_NORECORD which
01836                 means the operation can continue, but no undo information needs to be stored,
01837                 or AC_OK which means the operation should continue AND record undo information.
01838                 If the function returns AC_FAIL, there was not enough memory to record the 
01839                 undo information, and the user has decided not to continue with the operation.
01840     Errors:     -
01841     SeeAlso:    Action::Init()
01842 
01843 ********************************************************************************************/
01844 
01845 ActionCode RecordEnvelopeAction::Init(  Operation* pOp,
01846                                         ActionList* pActionList,
01847                                         MouldEnvelopeBase* pRecEnvelope,
01848                                         Action** NewAction)
01849 {
01850     ActionCode Ac = AC_FAIL;
01851     if (pRecEnvelope!=NULL)
01852     {
01853         UINT32 ActSize = sizeof(RecordEnvelopeAction);
01854         Ac = Action::Init( pOp, pActionList, ActSize, CC_RUNTIME_CLASS(RecordEnvelopeAction), NewAction);
01855         if (Ac==AC_OK)
01856         {
01857             RecordEnvelopeAction* pAct = ((RecordEnvelopeAction*)*NewAction);
01858             if (pAct)
01859             {
01860                 // Save a pointer to the Envelope and save the defining shape
01861                 pAct->pCEnvelope = pRecEnvelope;
01862                 pRecEnvelope->pEnvelope->CopyShape(pAct->RecordArray);
01863             }
01864         }
01865     }
01866     return Ac;
01867 }
01868 
01869 /********************************************************************************************
01870 
01871 >   ActionCode RecordEnvelopeAction::Execute()
01872 
01873     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01874     Created:    16/01/95
01875     Inputs:     -
01876     Outputs:    -
01877     Returns:    ActionCode, 
01878                     = AC_OK         if the action was created correctly
01879                     = AC_NORECORD   if no memory to undo/redo but go ahead anyway without undo
01880                     = AC_FAIL       stop the operation
01881     Purpose:    This is the virtual function that is called when the action is executed
01882                 by the Undo/Redo system. This is the function that actually undoes the envelope
01883                 change action by swapping the current internal definition of the envelope with
01884                 the contexts of itself.
01885     Errors:     -
01886     SeeAlso:    -
01887 
01888 ********************************************************************************************/
01889 
01890 ActionCode RecordEnvelopeAction::Execute()
01891 {
01892     // try to create a redo record
01893     RecordEnvelopeAction* EnvAction;
01894     ActionCode Act;
01895     Act = RecordEnvelopeAction::Init(pOperation, pOppositeActLst, pCEnvelope, (Action**)(&EnvAction));
01896     
01897     // for undo, simply copy 'this' record over the shape.
01898     // No No , we dont need to check for AC_OK, hands off! we've done all that in the
01899     // init function which tries to record the current state of the envelope
01900     if (pCEnvelope)
01901         pCEnvelope->BuildShape(RecordArray,NULL);
01902 
01903     return Act;
01904 }
01905 
01906 
01907 
01908 
01909 /********************************************************************************************
01910 
01911 >   static BOOL EnvelopeShapes::Rectangular(Path* pPath)
01912 
01913     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01914     Created:    11/12/94
01915     Inputs:     pPath = a pointer to an empty path (should be initialised but empty)
01916     Outputs:    pPath = a unit rectangular envelope, ready to be scaled to fit the selection.
01917     Returns:    TRUE    if the rectangular envelope manifold has been created
01918                 FALSE   if no memory to create the envelope.
01919 
01920     Purpose:    Creates a rectangular envelope. The envelope manifold is defined on a
01921                 millipoint square coordinate system. ie its outer coorinates are
01922                 (0,0), (72000,72000).
01923                 So to scale the envelope perform Coord = (ScaleFactor * Coord / 72000)
01924 
01925 ********************************************************************************************/
01926 
01927 BOOL EnvelopeShapes::Rectangular(Path* pPath)
01928 {
01929     ERROR2IF(pPath==NULL,FALSE,"NULL path pointer passed to EnvelopeShapes::Rectangular()");
01930 
01931     PathFlags flags;
01932     flags.IsSelected = FALSE;
01933 
01934     // Build a default rectangular manifold
01935     DocCoord point(0,0);
01936     BOOL ok = (pPath->AddMoveTo(point,&flags));
01937     if (!ok) return FALSE;
01938 
01939     point.y = 72000;
01940     ok = (pPath->AddCurveTo(point,&flags));
01941     if (!ok) return FALSE;
01942 
01943     point.x = 72000;
01944     ok = (pPath->AddCurveTo(point,&flags));
01945     if (!ok) return FALSE;
01946 
01947     point.y = 0;
01948     ok = (pPath->AddCurveTo(point,&flags));
01949     if (!ok) return FALSE;
01950 
01951     point.x = 0;
01952     ok = (pPath->AddCurveTo(point,&flags));
01953     if (!ok) return FALSE;
01954 
01955     ok = (pPath->CloseSubPath());
01956 
01957     return (ok);
01958 }
01959 
01960 
01961 /********************************************************************************************
01962 
01963 >   static BOOL EnvelopeShapes::Rectangular2x2(Path* pPath)
01964 
01965     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01966     Created:    11/12/94
01967     Inputs:     pPath = a pointer to an empty path (should be initialised but empty)
01968     Outputs:    pPath = a unit rectangular envelope, ready to be scaled to fit the selection.
01969     Returns:    TRUE    if the rectangular envelope manifold has been created
01970                 FALSE   if no memory to create the envelope.
01971 
01972     Purpose:    Creates a rectangular envelope. The envelope manifold is defined on a
01973                 millipoint square coordinate system. ie its outer coorinates are
01974                 (0,0), (72000,72000).
01975                 So to scale the envelope perform Coord = (ScaleFactor * Coord / 72000)
01976 
01977 ********************************************************************************************/
01978 
01979 BOOL EnvelopeShapes::Rectangular2x2(Path* pPath)
01980 {
01981     ERROR2IF(pPath==NULL,FALSE,"NULL path pointer passed to EnvelopeShapes::Rectangular()");
01982 
01983     PathFlags flags;
01984     flags.IsSelected = FALSE;
01985 
01986     // Build a default rectangular manifold
01987     DocCoord point(0,0);
01988     BOOL ok = (pPath->AddMoveTo(point,&flags));
01989     if (!ok) return FALSE;
01990 
01991     point.y = 72000/2;
01992     ok = (pPath->AddCurveTo(point,&flags));
01993     if (!ok) return FALSE;
01994 
01995     point.y = 72000;
01996     ok = (pPath->AddCurveTo(point,&flags));
01997     if (!ok) return FALSE;
01998 
01999     point.x = 72000/2;
02000     ok = (pPath->AddCurveTo(point,&flags));
02001     if (!ok) return FALSE;
02002 
02003     point.x = 72000;
02004     ok = (pPath->AddCurveTo(point,&flags));
02005     if (!ok) return FALSE;
02006 
02007     point.y = 72000/2;
02008     ok = (pPath->AddCurveTo(point,&flags));
02009     if (!ok) return FALSE;
02010 
02011     point.y = 0;
02012     ok = (pPath->AddCurveTo(point,&flags));
02013     if (!ok) return FALSE;
02014 
02015     point.x = 72000/2;
02016     ok = (pPath->AddCurveTo(point,&flags));
02017     if (!ok) return FALSE;
02018 
02019     point.x = 0;
02020     ok = (pPath->AddCurveTo(point,&flags));
02021     if (!ok) return FALSE;
02022 
02023     ok = (pPath->CloseSubPath());
02024 
02025     return (ok);
02026 }
02027 
02028 
02029 /********************************************************************************************
02030 
02031 >   static BOOL EnvelopeShapes::Circular(Path* pPath)
02032 
02033     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
02034     Created:    06/01/94
02035     Inputs:     pPath = a pointer to an empty path (should be initialised but empty)
02036     Outputs:    pPath = a unit cicular envelope, ready to be scaled to fit the selection.
02037     Returns:    TRUE    if the circular envelope manifold has been created
02038                 FALSE   if no memory to create the envelope.
02039 
02040     Purpose:    Creates a circular envelope. The envelope manifold is defined on a
02041                 millipoint square coordinate system. ie its outer coorinates are
02042                 (0,0), (72000,72000).
02043                 So to scale the envelope perform Coord = (ScaleFactor * Coord / 72000)
02044 
02045 ********************************************************************************************/
02046 
02047 BOOL EnvelopeShapes::Circular(Path* pPath)
02048 {
02049     ERROR2IF(pPath==NULL,FALSE,"NULL path pointer passed to EnvelopeShapes::Circular()");
02050 
02051     PathFlags flags;
02052     flags.IsSelected = FALSE;
02053     DocRect Rect (0,0,72000,72000);
02054     BOOL ok = MakeEllipse(&Rect, pPath, &flags);
02055 
02056     DocCoord* pCoords = pPath->GetCoordArray();
02057     INT32 numcoords = pPath->GetNumCoords();
02058 
02059     if (ok)
02060     {
02061         Matrix Mat0(-36000,-36000);
02062         Trans2DMatrix Trans0(Mat0);
02063         Trans0.Transform( pCoords, numcoords );
02064 
02065         ANGLE Ang = (ANGLE)(45);
02066         Matrix Mat1(Ang);
02067         Trans2DMatrix Trans1(Mat1);
02068         Trans1.Transform( pCoords, numcoords );
02069 
02070         Matrix Mat2(36000,36000);
02071         Trans2DMatrix Trans2(Mat2);
02072         Trans2.Transform( pCoords, numcoords );
02073     }
02074     else
02075         pPath->ClearPath();
02076 
02077     return ok;
02078 }
02079 
02080 
02081 
02082 /********************************************************************************************
02083 
02084 >   static BOOL EnvelopeShapes::Concave(Path* pPath)
02085 
02086     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
02087     Created:    06/01/94
02088     Inputs:     pPath = a pointer to an empty path (should be initialised but empty)
02089     Outputs:    pPath = a unit concave envelope, ready to be scaled to fit the selection.
02090     Returns:    TRUE    if the concave envelope manifold has been created
02091                 FALSE   if no memory to create the envelope.
02092 
02093     Purpose:    Creates a concave envelope. The envelope manifold is defined on a
02094                 millipoint square coordinate system. ie its outer coorinates are
02095                 (0,0), (72000,72000).
02096                 So to scale the envelope perform Coord = (ScaleFactor * Coord / 72000)
02097 
02098 ********************************************************************************************/
02099 
02100 BOOL EnvelopeShapes::Concave(Path* pPath)
02101 {
02102     ERROR2IF(pPath==NULL,FALSE,"NULL path pointer passed to EnvelopeShapes::Concave()");
02103 
02104     PathFlags flags;
02105     flags.IsSelected = FALSE;
02106     BOOL ok;
02107 
02108     DocRect Rect(0,0,72000,72000);
02109     DocCoord p1,p2,p3;
02110 
02111     DocCoord point(0,0);
02112     ok = (pPath->AddMoveTo(point,&flags));
02113     if (!ok) return FALSE;
02114 
02115     p1.x = (5 * Rect.lo.x + 3 * Rect.hi.x)/8;
02116     p1.y = (6 * Rect.lo.y + 2 * Rect.hi.y)/8;
02117     p2.x = p1.x;
02118     p2.y = (2 * Rect.lo.y + 6 * Rect.hi.y)/8;
02119     p3.x = Rect.lo.x;
02120     p3.y = Rect.hi.y;
02121 
02122     ok = (pPath->AddCurveTo(p1,p2,p3,&flags));
02123     if (!ok) return FALSE;
02124 
02125     point.x = 72000;
02126     point.y = 72000;
02127     ok = (pPath->AddLineTo(point,&flags));
02128     if (!ok) return FALSE;
02129 
02130     p1.x = (3*Rect.lo.x + 5*Rect.hi.x)/8;
02131     p1.y = (2*Rect.lo.y + 6*Rect.hi.y)/8;
02132     p2.x = p1.x;
02133     p2.y = (6*Rect.lo.y + 2*Rect.hi.y)/8;
02134     p3.x = Rect.hi.x;
02135     p3.y = Rect.lo.y;
02136 
02137     ok = (pPath->AddCurveTo(p1,p2,p3,&flags));
02138     if (!ok) return FALSE;
02139     
02140     point.x = 0;
02141     point.y = 0;
02142     ok = (pPath->AddLineTo(point,&flags));
02143     if (!ok) return FALSE;
02144 
02145     ok = (pPath->CloseSubPath());
02146 
02147     return ok;
02148 }
02149 
02150 
02151 /********************************************************************************************
02152 
02153 >   static BOOL EnvelopeShapes::Banner(Path* pPath)
02154 
02155     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
02156     Created:    06/01/94
02157     Inputs:     pPath = a pointer to an empty path (should be initialised but empty)
02158     Outputs:    pPath = a unit banner envelope, ready to be scaled to fit the selection.
02159     Returns:    TRUE    if the banner envelope manifold has been created
02160                 FALSE   if no memory to create the envelope.
02161 
02162     Purpose:    Creates a banner envelope. The envelope manifold is defined on a
02163                 millipoint square coordinate system. ie its outer coorinates are
02164                 (0,0), (72000,72000).
02165                 So to scale the envelope perform Coord = (ScaleFactor * Coord / 72000)
02166 
02167 ********************************************************************************************/
02168 
02169 BOOL EnvelopeShapes::Banner(Path* pPath)
02170 {
02171     ERROR2IF(pPath==NULL,FALSE,"NULL path pointer passed to EnvelopeShapes::Banner()");
02172 
02173     PathFlags flags;
02174     flags.IsSelected = FALSE;
02175     BOOL ok;
02176 
02177     DocRect Rect(0,0,72000,72000);
02178     DocCoord p1,p2,p3;
02179 
02180     DocCoord point(0,0);
02181     ok = (pPath->AddMoveTo(point,&flags));
02182     if (!ok) return FALSE;
02183 
02184     point.y = 72000;
02185     ok = (pPath->AddLineTo(point,&flags));
02186     if (!ok) return FALSE;
02187 
02188     p1.x = (6*Rect.lo.x + 2*Rect.hi.x)/8;
02189     p1.y = (3*Rect.lo.y + 5*Rect.hi.y)/8;
02190     p2.x = (2*Rect.lo.x + 6*Rect.hi.x)/8;
02191     p2.y = p1.y;
02192     p3.x = Rect.hi.x;
02193     p3.y = Rect.hi.y;
02194 
02195     ok = (pPath->AddCurveTo(p1,p2,p3,&flags));
02196     if (!ok) return FALSE;
02197 
02198     point.x = 72000;
02199     point.y = 0;
02200     ok = (pPath->AddLineTo(point,&flags));
02201     if (!ok) return FALSE;
02202 
02203     p1.x = (2*Rect.lo.x + 6*Rect.hi.x)/8;
02204     p1.y = (5*Rect.lo.y + 3*Rect.hi.y)/8;
02205     p2.x = (6*Rect.lo.x + 2*Rect.hi.x)/8;
02206     p2.y = p1.y;
02207     p3.x = Rect.lo.x;
02208     p3.y = Rect.lo.y;
02209 
02210     ok = (pPath->AddCurveTo(p1,p2,p3,&flags));
02211     if (!ok) return FALSE;
02212     
02213     ok = (pPath->CloseSubPath());
02214 
02215     return ok;
02216 }
02217 
02218 
02219 
02220 
02221 /*******************************************************************************************
02222 
02223 >   static BOOL EnvelopeShapes::MakeEllipse(DocRect* pRect, Path* pPath,PathFlags* pFlags)
02224 
02225     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
02226     Created:    06/01/95
02227     Inputs:     pRect  = a pointer to a rectangle to fit the ellipse in
02228                 pPath  = a pointer to an empty path (should be initialised but empty)
02229                 pFlags = flags to use for each path control point
02230     Outputs:    
02231     Purpose:    Create an elliptically shaped closed path which is the same size as and
02232                 has the same position as the rectangle specified.
02233 
02234 ********************************************************************************************/
02235 
02236 BOOL EnvelopeShapes::MakeEllipse(DocRect* pRect, Path* pPath, PathFlags* pFlags)
02237 {
02238     ERROR2IF(pRect==NULL,FALSE,"NULL rectangle pointer passed to EnvelopeShapes::MakeEllipse()");
02239     ERROR2IF(pPath==NULL,FALSE,"NULL path pointer passed to EnvelopeShapes::MakeEllipse()");
02240 
02241     DocCoord p0,p1,p2;
02242     INT32 dx,dy;
02243 
02244     dy = pRect->hi.y - pRect->lo.y;
02245     dx = pRect->hi.x - pRect->lo.x;
02246 
02247     double ratio = 1.0/4.4672;
02248 
02249     p0.x = pRect->lo.x;
02250     p0.y = pRect->lo.y + (INT32)(dy/2);
02251 
02252     BOOL ok = (pPath->AddMoveTo(p0,pFlags));
02253     if (!ok) return FALSE;
02254 
02255     p0.x = 0;
02256     p0.y = pRect->hi.y - (INT32)(dy*ratio);
02257     p1.x = pRect->lo.x + (INT32)(dx*ratio);
02258     p1.y = pRect->hi.y;
02259     p2.x = pRect->lo.x + (INT32)(dx/2);
02260     p2.y = pRect->hi.y;
02261 
02262     ok = (pPath->AddCurveTo(p0,p1,p2,pFlags));
02263     if (!ok) return FALSE;
02264 
02265     p0.x = pRect->hi.x - (INT32)(dx*ratio);
02266     p0.y = pRect->hi.y;
02267     p1.x = pRect->hi.x;
02268     p1.y = pRect->hi.y - (INT32)(dy*ratio);
02269     p2.x = pRect->hi.x;
02270     p2.y = pRect->lo.y + (INT32)(dy/2);
02271 
02272     ok = (pPath->AddCurveTo(p0,p1,p2,pFlags));
02273     if (!ok) return FALSE;
02274 
02275     p0.x = pRect->hi.x;
02276     p0.y = pRect->lo.y + (INT32)(dy*ratio);
02277     p1.x = pRect->hi.x - (INT32)(dx*ratio);
02278     p1.y = pRect->lo.y;
02279     p2.x = pRect->lo.x + (INT32)(dx/2);
02280     p2.y = pRect->lo.y;
02281 
02282     ok = (pPath->AddCurveTo(p0,p1,p2,pFlags));
02283     if (!ok) return FALSE;
02284 
02285     p0.x = pRect->lo.x + (INT32)(dx*ratio);
02286     p0.y = pRect->lo.y;
02287     p1.x = pRect->lo.x;
02288     p1.y = pRect->lo.y + (INT32)(dy*ratio);
02289     p2.x = pRect->lo.x; 
02290     p2.y = pRect->lo.y + (INT32)(dy/2);
02291 
02292     ok = (pPath->AddCurveTo(p0,p1,p2,pFlags));
02293     if (!ok) return FALSE;
02294 
02295     ok = (pPath->CloseSubPath());
02296 
02297     return ok;
02298 }
02299 
02300 

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