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