nodershp.cpp

Go to the documentation of this file.
00001 // $Id: nodershp.cpp 1776 2007-06-27 11:16:49Z luke $
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 
00099 /*
00100 */
00101 
00102 #include "camtypes.h"
00103 #include "nodershp.h"
00104 
00105 // Code headers
00106 //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00107 //#include "becomea.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00108 #include "blobs.h"
00109 #include "cameleps.h"
00110 #include "nativeps.h"       // The old style EPS native filter, used in v1.1
00111 #include "swfrndr.h"        // For the Flash render region class.
00112 #include "contmenu.h"
00113 //#include "docview.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00114 //#include "fillval.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00115 #include "nodepath.h"
00116 //#include "pathedit.h"
00117 #include "ophist.h"
00118 //#include "resource.h"
00119 //#include "rndrgn.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00120 #include "shapeops.h"
00121 #include "snap.h"
00122 //#include "tool.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00123 //#include "tranform.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00124 //#include "trans2d.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00125 
00126 // Headers for the new native format.
00127 //#include "cxfdefs.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00128 #include "cxfrgshp.h"
00129 
00130 // Resource headers.
00131 //#include "mario.h"     
00132 //#include "peter.h"
00133 //#include "rik.h"
00134 //#include "simon.h"
00135 
00136 // For ImagemapRenderRegion.
00137 #include "filtirr.h"
00138 
00139 #include "extender.h"
00140 
00141 // for the bounding box calculation.
00142 #include "attrmap.h"
00143 
00144 // for the variable width path fn.
00145 #include "strkattr.h"
00146 #include "ppstroke.h"
00147 #include "gclip.h"
00148 #include "gclips.h"
00149 #include "rsmooth.h"
00150 #include "brshattr.h"
00151 
00152 
00153 DECLARE_SOURCE( "$Revision: 1776 $" );
00154 
00155 
00156 CC_IMPLEMENT_DYNCREATE(NodeRegularShape, NodeRenderableInk)
00157 
00158 // Declare smart memory handling in Debug builds
00159 #define new CAM_DEBUG_NEW
00160 
00161 static const double CurveFactor = 0.552;
00162 
00163 /***********************************************************************************************
00164 
00165 >   NodeRegularShape::NodeRegularShape(Node*    ContextNode,
00166                         AttachNodeDirection Direction,
00167                         const DocRect&      BoundingRect,
00168                         BOOL                Locked = FALSE,
00169                         BOOL                Mangled = FALSE,
00170                         BOOL                Marked = FALSE,
00171                         BOOL                Selected = FALSE,
00172                         BOOL                Renderable = FALSE
00173                         )
00174 
00175     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00176     Created:    16/11/94
00177     Inputs:     ContextNode: Pointer to a node which this node is to be attached to.
00178                 MonoOn Direction: MonoOff
00179                 Specifies the direction in which the node is to be attached to the
00180                 ContextNode. The values this variable can take are as follows:
00181                                   
00182                 PREV      : Attach node as a previous sibling of the context node
00183                 NEXT      : Attach node as a next sibling of the context node
00184                 FIRSTCHILD: Attach node as the first child of the context node
00185                 LASTCHILD : Attach node as a last child of the context node
00186 
00187                 BoundingRect: Bounding rectangle
00188 
00189                 The remaining inputs specify the status of the node:
00190             
00191                 Locked:     Is node locked ?
00192                 Mangled:    Is node mangled ?
00193                 Marked:     Is node marked ?
00194                 Selected:   Is node selected ?
00195 
00196     Purpose:    This constructor initialises the nodes flags and links it to ContextNode in the
00197                 direction specified by Direction. All neccesary tree links are updated.
00198     Note:       SetUpShape() must be called before the NodeRegularShape is in a state in which
00199                 it can be used.
00200     SeeAlso:    NodeRegularShape::SetUpShape
00201     Errors:     An ENSURE will occur if ContextNode is NULL
00202 
00203 ***********************************************************************************************/
00204 NodeRegularShape::NodeRegularShape(Node* ContextNode,  
00205                     AttachNodeDirection Direction,  
00206                     BOOL Locked, 
00207                     BOOL Mangled,  
00208                     BOOL Marked, 
00209                     BOOL Selected    
00210               ) : NodeRenderableInk(ContextNode, Direction, Locked, Mangled, Marked, Selected )
00211 {                         
00212     InitialiseMemberVars();
00213 }                        
00214  
00215 
00216 
00217 /*********************************************************************************************
00218 
00219 >   NodeRegularShape::NodeRegularShape() 
00220 
00221     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00222     Created:    16/11/94
00223     Purpose:    This constructor creates a NodeRegularShape linked to no other.
00224     Note:       SetUpShape() should be called to change the NodeRegularShape before use!
00225     SeeAlso:    NodeRegularShape::SetUpShape                                                        
00226 
00227 **********************************************************************************************/
00228 NodeRegularShape::NodeRegularShape() : NodeRenderableInk()
00229 {
00230     InitialiseMemberVars();
00231 }
00232 
00233 
00234 
00235 /*********************************************************************************************
00236 
00237 >   void NodeRegularShape::InitialiseMemberVars()
00238 
00239     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00240     Created:    18/6/96
00241     Inputs:     -
00242     Outputs:    Initalised member variables
00243     Returns:    -
00244     Purpose:    One consistant place to initialise all the member variables of a NodeRegularShape
00245 
00246 **********************************************************************************************/
00247 void NodeRegularShape::InitialiseMemberVars()
00248 {
00249     Circular = FALSE;   
00250     Stellated = FALSE;  
00251     PrimaryCurvature = FALSE;   
00252     StellationCurvature = FALSE;
00253     NumSides = 6;           
00254     StellRadiusToPrimary = 0.5;
00255     PrimaryCurveToPrimary = 0.2;
00256     StellCurveToStell = 0.2;
00257     StellOffsetRatio = 0.0;
00258     CachedRenderPath = NULL;
00259     PathCacheInvalid = TRUE;
00260 }
00261 
00262 
00263 
00264 /*********************************************************************************************
00265 
00266 >   NodeRegularShape::~NodeRegularShape() 
00267 
00268     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00269     Created:    31/1/95
00270     Purpose:    Distructor to delete the cached render path
00271     SeeAlso:    -
00272 
00273 **********************************************************************************************/
00274 NodeRegularShape::~NodeRegularShape()
00275 {
00276     DeleteCachedPath();
00277 }
00278 
00279 
00280 
00281 /***********************************************************************************************
00282 
00283 >   virtual Node* NodeRegularShape::SimpleCopy()
00284 
00285     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00286     Created:    16/11/94
00287     Returns:    Pointer to a Node or NULL if there was not enough memory for the new node
00288     Purpose:    Makes a copy of all the data in the node
00289 
00290 ***********************************************************************************************/
00291 
00292 Node* NodeRegularShape::SimpleCopy()
00293 {
00294     // Make a new NodeRegularShape and then copy things into it
00295     NodeRegularShape* NodeCopy = new NodeRegularShape();
00296     if (NodeCopy != NULL)
00297         CopyNodeContents(NodeCopy);
00298 
00299     return NodeCopy;
00300 }            
00301 
00302 
00303 
00304 /***********************************************************************************************
00305 
00306 >   void NodeRegularShape::CopyNodeContents(NodeRegularShape* NodeCopy)
00307 
00308     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00309     Created:    16/11/94
00310     Inputs:     NodeCopy - The node to copy the data into
00311     Purpose:    Copies the data in the node by first calling the base class to get it to
00312                 copy its stuff, and then copying its own stuff
00313                 Note : Copies FROM this TO NodeCopy
00314     SeeAlso:    NodeRenderableInk::CopyNodeContents
00315     Errors:     ERROR3 if passed a NULL pointer.
00316 
00317 ***********************************************************************************************/
00318 
00319 void NodeRegularShape::CopyNodeContents(NodeRegularShape* NodeCopy)
00320 {
00321     ERROR3IF(NodeCopy == NULL,"NodeRegularShape::CopyNodeContents was asked to copy into a NULL pointer");
00322 
00323     // If the dest shape has any cached object pointers, delete them before copying over
00324     delete NodeCopy->CachedRenderPath;
00325     
00326     // Copy from the base class
00327     NodeRenderableInk::CopyNodeContents(NodeCopy);
00328     
00329     //Copy contents specific to derived class here
00330     NodeCopy->NumSides = NumSides;              
00331     NodeCopy->Circular = Circular;              
00332     NodeCopy->Stellated = Stellated;            
00333     NodeCopy->PrimaryCurvature = PrimaryCurvature;      
00334     NodeCopy->StellationCurvature = StellationCurvature;    
00335     NodeCopy->StellRadiusToPrimary = StellRadiusToPrimary;  
00336     NodeCopy->PrimaryCurveToPrimary = PrimaryCurveToPrimary;    
00337     NodeCopy->StellCurveToStell = StellCurveToStell;    
00338     NodeCopy->StellOffsetRatio = StellOffsetRatio;
00339     NodeCopy->UTCentrePoint = UTCentrePoint;
00340     NodeCopy->UTMajorAxes = UTMajorAxes;
00341     NodeCopy->UTMinorAxes = UTMinorAxes;
00342     NodeCopy->CachedRenderPath = NULL;
00343     NodeCopy->PathCacheInvalid = TRUE;
00344     NodeCopy->TransformMatrix = TransformMatrix;
00345 
00346     // When copying the paths we could run out of memory (so?)
00347     if (NodeCopy->EdgePath1.Initialise(EdgePath1.GetNumCoords(),1) 
00348         && NodeCopy->EdgePath2.Initialise(EdgePath2.GetNumCoords(),1) )
00349     {
00350         NodeCopy->EdgePath1.CopyPathDataFrom(&EdgePath1);
00351         NodeCopy->EdgePath2.CopyPathDataFrom(&EdgePath2);
00352     }
00353 }
00354 
00355 
00356 
00357 /***********************************************************************************************
00358 >   void NodeRegularShape::PolyCopyNodeContents(NodeRenderable* pNodeCopy)
00359 
00360     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00361     Created:    18/12/2003
00362     Outputs:    -
00363     Purpose:    Polymorphically copies the contents of this node to another
00364     Errors:     An assertion failure will occur if NodeCopy is NULL
00365     Scope:      protected
00366                                      
00367 ***********************************************************************************************/
00368 
00369 void NodeRegularShape::PolyCopyNodeContents(NodeRenderable* pNodeCopy)
00370 {
00371     ENSURE(pNodeCopy, "Trying to copy a node's contents into a NULL node");
00372     ENSURE(IS_A(pNodeCopy, NodeRegularShape), "PolyCopyNodeContents given wrong dest node type");
00373 
00374     if (IS_A(pNodeCopy, NodeRegularShape))
00375         CopyNodeContents((NodeRegularShape*)pNodeCopy);
00376 }
00377 
00378 
00379 
00380 /***********************************************************************************************
00381 
00382 >   void NodeRegularShape::ShowDebugTreeDetails() const
00383 
00384     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00385     Created:    16/11/94
00386     Purpose:    Displays debugging info of the tree
00387     SeeAlso:    NodeRenderableInk::ShowDebugTreeDetails
00388 
00389 ***********************************************************************************************/
00390 #ifdef _DEBUG
00391 void NodeRegularShape::ShowDebugTreeDetails() const
00392 {                     
00393     // Display a bit of debugging info
00394     // For now, we will just call the base class version
00395     TRACEALL( _T("NodeRegularShape  ") );
00396     NodeRenderableInk::ShowDebugTreeDetails();  
00397 }
00398 #endif
00399 
00400 
00401 
00402 /********************************************************************************************
00403 
00404 >   void NodeRegularShape::GetDebugDetails( StringBase* Str )
00405 
00406     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00407     Created:    16/11/94
00408     Outputs:    Str: String giving debug info about the node
00409     Purpose:    For obtaining debug information about the Node (for
00410 
00411 ********************************************************************************************/
00412 
00413 void NodeRegularShape::GetDebugDetails( StringBase* Str )
00414 {
00415 #if DEBUG_TREE
00416     // Call base class
00417     NodeRenderableInk::GetDebugDetails( Str );
00418     
00419     String_256 TempStr;
00420     String_256 TempStr2;
00421         
00422     (*Str) += TEXT( "\r\nRegular Path Data Dump\r\n" );
00423 
00424     DocRect BlobRect = GetBlobBoundingRect();
00425     TempStr._MakeMsg( TEXT("Blob Bounding Rect :\r\n\t#1%ld,\t#2%ld\r\n\t#3%ld,\t#4%ld\r\n"),
00426                       BlobRect.lo.x, BlobRect.lo.y, BlobRect.hi.x, BlobRect.hi.y );
00427     (*Str) += TempStr;
00428 
00429     TempStr._MakeMsg( TEXT("#1%d sides\r\n"),NumSides);
00430     (*Str) += TempStr;
00431 
00432     TempStr._MakeMsg( TEXT("Set Flags:"));
00433     if (Circular)
00434     {
00435         TempStr2._MakeMsg( TEXT(" Circular"));
00436         TempStr += TempStr2;
00437     }
00438     if (Stellated)
00439     {
00440         TempStr2._MakeMsg( TEXT(" Stellated"));
00441         TempStr += TempStr2;
00442     }
00443     if (PrimaryCurvature)
00444     {
00445         TempStr2._MakeMsg( TEXT(" PrimaryCurvature"));
00446         TempStr += TempStr2;
00447     }
00448     if (StellationCurvature)
00449     {
00450         TempStr2._MakeMsg( TEXT(" StellationCurvature"));
00451         TempStr += TempStr2;
00452     }
00453     if (!(Circular || Stellated || PrimaryCurvature || StellationCurvature))
00454     {
00455         TempStr2._MakeMsg( TEXT(" None! "));
00456         TempStr += TempStr2;
00457     }
00458     TempStr2._MakeMsg( TEXT("\r\n\r\n"));
00459     TempStr += TempStr2;
00460     (*Str) += TempStr;
00461 
00462     TCHAR               floatStr[20];
00463     camSnprintf( floatStr, 20, _T("%f"), StellRadiusToPrimary );
00464     TempStr._MakeMsg( TEXT("Stellation Radius :\t#1%s\r\n"), floatStr);
00465     (*Str) += TempStr;
00466     camSnprintf( floatStr, 20, _T("%f"), StellOffsetRatio );
00467     TempStr._MakeMsg( TEXT("Stellation Offset :\t#1%s\r\n\r\n"), floatStr);
00468     (*Str) += TempStr;
00469     camSnprintf( floatStr, 20, _T("%f"), PrimaryCurveToPrimary);
00470     TempStr._MakeMsg( TEXT("Primary Curvature :\t#1%s\r\n"), floatStr);
00471     (*Str) += TempStr;
00472     camSnprintf( floatStr, 20, _T("%f"), StellCurveToStell);
00473     TempStr._MakeMsg( TEXT("Stellation Curvature :\t#1%s\r\n"), floatStr);
00474     (*Str) += TempStr;
00475 
00476     TempStr._MakeMsg( TEXT("\r\nUntransformed"));
00477     (*Str) += TempStr;
00478     TempStr._MakeMsg( TEXT("Centre Point :\t#1%ld,\t#2%ld\r\n"), UTCentrePoint.x, UTCentrePoint.y);
00479     (*Str) += TempStr;
00480     TempStr._MakeMsg( TEXT("Major axes :\t#1%ld,\t#2%ld\r\n"), UTMajorAxes.x, UTMajorAxes.y);
00481     (*Str) += TempStr;
00482     TempStr._MakeMsg( TEXT("Minor axes :\t#1%ld,\t#2%ld\r\n"), UTMinorAxes.x, UTMinorAxes.y);
00483     (*Str) += TempStr;
00484     
00485     TempStr._MakeMsg( TEXT("\r\nTransformed"));
00486     (*Str) += TempStr;
00487     TempStr._MakeMsg( TEXT("Centre Point :\t#1%ld,\t#2%ld\r\n"), GetCentrePoint().x, GetCentrePoint().y);
00488     (*Str) += TempStr;
00489     TempStr._MakeMsg( TEXT("Major axes :\t#1%ld,\t#2%ld\r\n"), GetMajorAxes().x, GetMajorAxes().y);
00490     (*Str) += TempStr;
00491     TempStr._MakeMsg( TEXT("Minor axes :\t#1%ld,\t#2%ld\r\n"), GetMinorAxes().x, GetMinorAxes().y);
00492     (*Str) += TempStr;
00493 
00494     fixed16 billy[4];
00495     INT32   bobby[2];
00496     TransformMatrix.GetComponents(billy, bobby);
00497 
00498     TempStr._MakeMsg( TEXT("\r\nMatrix\r\n"));   
00499     (*Str) += TempStr;
00500     camSnprintf( floatStr, 20, _T("%f,%f"), billy[0].MakeDouble(), billy[1].MakeDouble());
00501     TempStr._MakeMsg( TEXT("a, b :\t#1%s\r\n"), floatStr);
00502     (*Str) += TempStr;
00503     camSnprintf( floatStr, 20, _T("%f,%f"), billy[2].MakeDouble(), billy[3].MakeDouble());
00504     TempStr._MakeMsg( TEXT("c, d :\t#1%s\r\n"), floatStr);
00505     (*Str) += TempStr;
00506     TempStr._MakeMsg( TEXT("e, f :\t#1%ld,\t#2%ld\r\n"), bobby[0], bobby[1]);
00507     (*Str) += TempStr;
00508 
00509     (*Str) += TEXT( "\r\nPath 1\r\nNum\tType\tX Coord\tY Coord\r\n" );
00510     PathVerb* Verbs  = EdgePath1.GetVerbArray();
00511     DocCoord* Coords = EdgePath1.GetCoordArray();
00512     PathFlags* Flags = EdgePath1.GetFlagArray();
00513     INT32                   i;
00514     for( i = 0; i<EdgePath1.GetNumCoords(); i++)
00515     {
00516         // Add the info to the string
00517         TempStr._MakeMsg( TEXT("#1%d.\t#2%d\t#3%ld,\t#4%ld\r\n"),
00518                           i, Verbs[i], Coords[i].x, Coords[i].y );
00519         (*Str) += TempStr;
00520     }
00521 
00522     (*Str) += TEXT( "\r\nPath 2\r\nNum\tType\tX Coord\tY Coord\r\n" );
00523     Verbs  = EdgePath2.GetVerbArray();
00524     Coords = EdgePath2.GetCoordArray();
00525     Flags = EdgePath2.GetFlagArray();
00526     for (i=0; i<EdgePath2.GetNumCoords(); i++)
00527     {
00528         // Add the info to the string
00529         TempStr._MakeMsg( TEXT("#1%d.\t#2%d\t#3%ld,\t#4%ld\r\n"),
00530                           i, Verbs[i], Coords[i].x, Coords[i].y );
00531         (*Str) += TempStr;
00532     }
00533 
00534     Path* RenderPath = NULL;
00535     if (BuildShapePath(&RenderPath))
00536     {
00537         // Now do the complete path shape
00538         (*Str) += TEXT( "\r\nRender path\r\nNum\tType\tX Coord\tY Coord\r\n" );
00539         Verbs  = RenderPath->GetVerbArray();
00540         Coords = RenderPath->GetCoordArray();
00541         Flags = RenderPath->GetFlagArray();
00542         for (i=0; i<RenderPath->GetNumCoords(); i++)
00543         {
00544             // Add the info to the string
00545             TempStr._MakeMsg( TEXT("#1%d.\t#2%d\t#3%ld,\t#4%ld\r\n"),
00546                               i, Verbs[i], Coords[i].x, Coords[i].y );
00547             (*Str) += TempStr;
00548         }
00549     }
00550     else
00551     {
00552         TempStr._MakeMsg( TEXT("Failed to build render path") );
00553         (*Str) += TempStr;
00554     }
00555 #endif
00556 }
00557 
00558 
00559 
00560 /***********************************************************************************************
00561 
00562 >   BOOL NodeRegularShape::SetUpShape()
00563 
00564     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00565     Created:    16/11/94
00566     Inputs:     - 
00567     Returns:    TRUE if the shape was init'ed ok, FALSE otherwise
00568     Purpose:    To initialise the paths used by the shape into a state that can be used,
00569                 by allocating memory, setting up member variables properly.
00570 
00571 ***********************************************************************************************/
00572 
00573 BOOL NodeRegularShape::SetUpShape()
00574 {
00575     if (EdgePath1.Initialise(4, 1) && EdgePath2.Initialise(4, 1))
00576     {
00577         DocCoord Fred1(0,0);
00578         DocCoord Fred2(72000,0);
00579         EdgePath1.SetPathPosition(0);
00580         EdgePath1.InsertMoveTo(Fred1);
00581         EdgePath1.InsertLineTo(Fred2);
00582         EdgePath2.SetPathPosition(0);
00583         EdgePath2.InsertMoveTo(Fred1);
00584         EdgePath2.InsertLineTo(Fred2);
00585         return TRUE;
00586     }
00587     else
00588         return FALSE;
00589 }
00590 
00591 
00592 
00593 /********************************************************************************************
00594 
00595 >   virtual void NodeRegularShape::Transform( TransformBase& Trans )
00596 
00597     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00598     Created:    21/11/94
00599     Inputs:     Trans - The transform Object
00600     Purpose:    Transforms the shape.
00601     SeeAlso:    NodeRenderableInk::Transform()
00602 
00603 ********************************************************************************************/
00604 void NodeRegularShape::Transform( TransformBase& Trans )
00605 {
00606     if (IS_A(&Trans, Trans2DMatrix))
00607     {
00608         TransformMatrix *= ((Trans2DMatrix&)Trans).GetMatrix();
00609     }
00610     else
00611     {
00612         // Transform the Shape
00613         Trans.Transform(&UTCentrePoint, 1);
00614         Trans.Transform(&UTMajorAxes, 1);
00615         Trans.Transform(&UTMinorAxes, 1);
00616     }
00617 
00618     EmergencyFixShape();
00619 
00620     // Mark the bounding rect as invalid                            
00621     InvalidateBoundingRect();
00622     InvalidateCache();
00623 
00624     DocRect dr = GetBoundingRect();
00625     
00626     // Transform all the children...
00627     TransformChildren(Trans);
00628 
00629     InvalidateBoundingRect();
00630     InvalidateCache();
00631     dr = GetBoundingRect();
00632 }
00633 
00634 
00635 
00636 /********************************************************************************************
00637 
00638 >   virtual void NodeRegularShape::TransformCentreAndAxes( TransformBase& Trans )
00639 
00640     Author:     Rory
00641     Created:    21/05/07
00642     Inputs:     Trans - The transform Object
00643     Purpose:    Transforms the shape centre point and axes without modifying the matrix.
00644     SeeAlso:    NodeRegularShape::Transform()
00645 
00646 ********************************************************************************************/
00647 void NodeRegularShape::TransformCentreAndAxes( TransformBase& Trans )
00648 {
00649     // Apply the transform to the transformed centre point and axes
00650     TransformMatrix.transform(&UTCentrePoint);
00651     Trans.Transform(&UTCentrePoint, 1);
00652     TransformMatrix.Inverse().transform(&UTCentrePoint);
00653 
00654     TransformMatrix.transform(&UTMajorAxes);
00655     Trans.Transform(&UTMajorAxes, 1);
00656     TransformMatrix.Inverse().transform(&UTMajorAxes);
00657 
00658     TransformMatrix.transform(&UTMinorAxes);
00659     Trans.Transform(&UTMinorAxes, 1);
00660     TransformMatrix.Inverse().transform(&UTMinorAxes);
00661 
00662     EmergencyFixShape();
00663 
00664     // Mark the bounding rect as invalid                            
00665     InvalidateBoundingRect();
00666     InvalidateCache();
00667 }
00668 
00669 
00670 
00671 /***********************************************************************************************
00672 
00673 >   BOOL NodeRegularShape::BuildShapePath(Path** RenderPath)
00674 
00675     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00676     Created:    16/11/94
00677     Inputs:     RenderPath - Pointer to an pointer to a Path object.
00678     Outputs:    RenderPath will point to a path that describes the whole regular shape.  This can
00679                 then be used to render the shape or EOR its outline.
00680     Returns:    FALSE if the path could not be created (eg out of memory).  TRUE if RenderPath
00681                 points to a valid path.
00682     Purpose:    Will build up a path representing the path from the edge paths stored in the
00683                 NodeRegularShape object.
00684                 NOTES: This rountine needs to be as quick as possible as it is called all the
00685                 time anyone does anything involving the path.  It may be necessary to hold
00686                 the render path in the shape and only regenerate it when required.
00687     SeeAlso:    RegShape.doc
00688     Errors:     SetError will have been called if FALSE is returned.
00689 
00690 ***********************************************************************************************/
00691 
00692 BOOL NodeRegularShape::BuildShapePath(Path** RenderPath)
00693 { 
00694     if ((CachedRenderPath == NULL) || PathCacheInvalid)
00695     {
00696         DeleteCachedPath();
00697 
00698         CachedRenderPath = new (Path);
00699         if (CachedRenderPath == NULL)
00700             return FALSE;
00701 
00702         BOOL Success = TRUE;
00703     
00704         if (IsCircular())
00705         {
00706             Success = BuildEllipsePath(CachedRenderPath);
00707         }
00708         else
00709         {
00710             DocCoord*   pArray;
00711             Success = BuildPolygonPoints(&pArray);
00712             if (Success)
00713                 Success = BuildPolygonPath(CachedRenderPath, pArray);
00714             if (pArray != NULL)
00715                 delete [] pArray;
00716         }
00717 
00718         if (Success)
00719         {
00720             DocCoord* Coords = CachedRenderPath->GetCoordArray();
00721             TransformMatrix.transform((Coord*)Coords, CachedRenderPath->GetNumCoords()); 
00722 
00723             *RenderPath = CachedRenderPath;
00724             PathCacheInvalid = FALSE;
00725             return TRUE;
00726         }
00727         else
00728         {
00729             DeleteCachedPath();
00730             return FALSE;
00731         }
00732     }
00733     else
00734     {
00735         *RenderPath = CachedRenderPath;
00736         return TRUE;
00737     }
00738 }
00739 
00740 
00741 
00742 /********************************************************************************************
00743 
00744 >   void NodeRegularShape::Render ( RenderRegion* pRender )
00745 
00746     Author:     Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com>
00747     Created:    9/6/00
00748     Inputs:     pRender - Pointer to a render region.
00749     Purpose:    Creates a path from the renderable shape's characterisitics, which it passes
00750                 to the DrawPath method of the render region that it's exporting to.
00751 
00752 ********************************************************************************************/
00753 void NodeRegularShape::Render ( RenderRegion* pRender )
00754 {
00755     Path* pRenderPath = NULL;
00756 
00757     // Attempt to build a shape path.
00758     if ( BuildShapePath ( &pRenderPath ) )
00759     {
00760         // Write the path out to the file.
00761         pRender->DrawPath ( pRenderPath, NULL, GetPathShape () );
00762     }
00763 }  
00764 
00765 
00766 
00767 /********************************************************************************************
00768 
00769 >   void NodeRegularShape::RenderEorDrag( RenderRegion* pRender )
00770 
00771     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00772     Created:    16/11/94
00773     Inputs:     pRender - A Pointer to the current RenderRegion
00774     Purpose:    Renders a version of the shape for EORed dragging.
00775     SeeAlso:    NodeRenderableInk::RenderEorDrag
00776 
00777 ********************************************************************************************/
00778 void NodeRegularShape::RenderEorDrag( RenderRegion* pRender )
00779 {
00780     Path* RenderPath = NULL;
00781     
00782     if (BuildShapePath(&RenderPath))
00783         pRender->DrawPath(RenderPath);
00784 }
00785 
00786 
00787 
00788 /********************************************************************************************
00789 
00790 >   void NodeRegularShape::RenderObjectBlobs(RenderRegion* pRender)
00791 
00792     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00793     Created:    16/11/94
00794     Inputs:     pRender - the region to render the blobs to
00795     Purpose:    Renders the Object blobs for a NodeRegularShape
00796     SeeAlso:    BlobManager
00797 
00798 ********************************************************************************************/
00799 void NodeRegularShape::RenderObjectBlobs(RenderRegion* pRender)
00800 {
00801     pRender->SetLineColour(COLOUR_UNSELECTEDBLOB);
00802     pRender->SetFillColour(COLOUR_UNSELECTEDBLOB);
00803 
00804     // Draw a blob at the centre point
00805     DocRect BlobSize;
00806     BlobManager* pBlobMgr = GetApplication()->GetBlobManager();
00807     if (pBlobMgr != NULL)
00808     {
00809         DocCoord Point = GetCentrePoint();
00810         pBlobMgr->GetBlobRect(Point, &BlobSize);
00811 
00812         pRender->DrawLine(DocCoord(BlobSize.hi.x, BlobSize.hi.y), DocCoord(BlobSize.lo.x, BlobSize.lo.y));
00813         pRender->DrawLine(DocCoord(BlobSize.lo.x, BlobSize.hi.y), DocCoord(BlobSize.hi.x, BlobSize.lo.y));
00814         pRender->DrawPixel(DocCoord(BlobSize.hi.x, BlobSize.lo.y));
00815         pRender->DrawPixel(DocCoord(BlobSize.lo.x, BlobSize.lo.y));
00816     }
00817 
00818     pRender->SetLineColour(COLOUR_NONE);
00819     // Now draw blobs at the primary and stellation points, and their curvature points.
00820     if (!IsCircular())
00821     {
00822         DocCoord*   Array;
00823         INT32 Points = 0;
00824         BOOL Success = BuildPolygonPoints(&Array, &Points);
00825         UINT32 Counter = 0;
00826         if (Success)
00827         {
00828             TransformMatrix.transform((Coord*)Array, Points);
00829             for (UINT32 loop = 0; loop < NumSides; loop++)
00830             {
00831                 // Skip along to the stellation information
00832                 Counter ++;
00833                 if (IsPrimaryCurvature())
00834                     Counter ++;
00835 
00836                 if (IsStellated())
00837                 {
00838                     if (IsStellationCurvature())
00839                     {
00840                         pRender->DrawBlob(Array[Counter], BT_UNSELECTED);
00841                         pRender->DrawBlob(Array[Counter+1], BT_UNSELECTED);
00842                         pRender->DrawBlob(Array[Counter+2], BT_UNSELECTED);
00843                         pRender->SetLineColour(COLOUR_BEZIERLINE);
00844                         pRender->DrawLine(Array[Counter], Array[Counter+1]);
00845                         pRender->DrawLine(Array[Counter+1], Array[Counter+2]);
00846                         pRender->SetLineColour(COLOUR_NONE);
00847                         Counter += 3;
00848                     }           
00849                     else
00850                         pRender->DrawBlob(Array[Counter++], BT_UNSELECTED);
00851                 }
00852 
00853                 if (IsPrimaryCurvature())
00854                 {
00855                     pRender->DrawBlob(Array[Counter], BT_UNSELECTED);
00856                     pRender->DrawBlob(Array[Counter+1], BT_UNSELECTED);
00857                     pRender->DrawBlob(Array[Counter+2], BT_UNSELECTED);
00858                     pRender->SetLineColour(COLOUR_BEZIERLINE);
00859                     pRender->DrawLine(Array[Counter], Array[Counter+1]);
00860                     pRender->DrawLine(Array[Counter+1], Array[Counter+2]);
00861                     pRender->SetLineColour(COLOUR_NONE);
00862                     Counter ++;
00863                 }
00864                 else
00865                     pRender->DrawBlob(Array[Counter], BT_UNSELECTED);
00866             }
00867         }
00868         if (Array != NULL)
00869             delete [] Array;
00870     }
00871     else
00872     {
00873         pRender->DrawBlob(GetMinorAxes(), BT_UNSELECTED);
00874         pRender->DrawBlob(GetMajorAxes(), BT_UNSELECTED);
00875         pRender->DrawBlob(GetCentrePoint() - (GetMajorAxes() - GetCentrePoint()), BT_UNSELECTED);
00876         pRender->DrawBlob(GetCentrePoint() - (GetMinorAxes() - GetCentrePoint()), BT_UNSELECTED);
00877     }
00878 }
00879 
00880 
00881 
00882 /********************************************************************************************
00883 
00884 >   void NodeRegularShape::RenderTinyBlobs(RenderRegion* pRender)
00885 
00886     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00887     Created:    16/11/94
00888     Inputs:     pRender - the region to render the blobs to
00889     Purpose:    Renders the Tiny blobs for a NodeRegularShape
00890     SeeAlso:    BlobManager
00891 
00892 ********************************************************************************************/
00893 
00894 void NodeRegularShape::RenderTinyBlobs(RenderRegion* pRender)
00895 {
00896     // Set the line colours etc as we need them
00897     pRender->SetLineColour(COLOUR_NONE);
00898     pRender->SetFillColour(COLOUR_UNSELECTEDBLOB);
00899 
00900     Path* RenderPath = NULL;
00901     if (BuildShapePath(&RenderPath))
00902     {
00903         // Find out about the path that the shape is made from
00904         DocCoord* Coords = RenderPath->GetCoordArray();
00905 
00906         // Render a blob on the first moveto
00907         pRender->DrawBlob(Coords[0], BT_UNSELECTED);
00908     }
00909 }
00910 
00911 
00912 
00913 /********************************************************************************************
00914 
00915 >   DocRect NodeRegularShape::GetBoundingRect(BOOL DontUseAttrs=FALSE, BOOL HitTest=FALSE)
00916 
00917     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00918     Created:    16/11/94
00919     Inputs:     DontUseAttrs - TRUE if we should ignore the nodes attributes.
00920                 Defaults to FALSE
00921     Returns:    The nodes bounding rect
00922     Purpose:    if the bounding rect is valid it is returned, if not, it is recalculated
00923                 and then returned.
00924     SeeAlso:    NodeRegularShape::GetBlobBoundingRect
00925 
00926 ********************************************************************************************/
00927 DocRect NodeRegularShape::GetBoundingRect(BOOL DontUseAttrs, BOOL HitTest)
00928 {
00929     // Something to put the new bounding rectangle in
00930     DocRect NewBoundingRect(GetCentrePoint(),GetCentrePoint());
00931     
00932     if (!IsBoundingRectValid || DontUseAttrs)
00933     {
00934         Path* RenderPath = NULL;
00935         BuildShapePath(&RenderPath);
00936 
00937         // Find out what the paths bounding rect is now
00938         if (!CalculatePathBoundingRect(*RenderPath, DontUseAttrs, &NewBoundingRect))
00939         {
00940             // GDraw failed to find out how big the bounding rect
00941             // we will have to make do with the bounding rect of the coords
00942             NewBoundingRect = RenderPath->GetBoundingRect();
00943         }
00944 
00945         // we have a new bounding rect - decide what to do with it
00946         if (DontUseAttrs)
00947         {
00948             // but it is not the real bounding rect, so just return it
00949             return NewBoundingRect;
00950         }
00951         else
00952         {
00953             // We need to go though the attributes applied to this path,
00954             // and see if any of them effect the bounding rect
00955             // (eg. ArrowHeads)
00956             CCAttrMap AttribMap(30);
00957             if (FindAppliedAttributes(&AttribMap))
00958             {
00959                 CCRuntimeClass *pType;
00960                 void *pVal;
00961 
00962                 // iterating all (key, value) pairs
00963                 for( CCAttrMap::iterator Pos = AttribMap.GetStartPosition(); Pos != AttribMap.GetEndPosition(); )
00964                 {
00965                     // Get attr at position Pos
00966                     AttribMap.GetNextAssoc(Pos,pType,pVal);
00967 
00968                     if (pVal != NULL)
00969                     {
00970                         if ( ((NodeAttribute*)pVal)->EffectsParentBounds() )
00971                         {
00972                             // Get the bounds of the attribute and Union it with
00973                             // the path bounds
00974                             DocRect AttrBounds = 
00975                                 ((NodeAttribute*)pVal)->GetAttrBoundingRect(this, &AttribMap);
00976                             NewBoundingRect = NewBoundingRect.Union(AttrBounds);
00977                         }
00978                     }
00979                 }
00980             }
00981         }
00982 
00983         // Update the Nodes bounding rectangle
00984         BoundingRectangle = NewBoundingRect;
00985 
00986         // Mark the rect as valid
00987         IsBoundingRectValid = TRUE;
00988     }
00989     // return the current state of the bounding rect
00990     return BoundingRectangle;
00991 }
00992 
00993 
00994 
00995 /********************************************************************************************
00996 
00997 >   DocRect NodeRegularShape::GetBlobBoundingRect()
00998 
00999     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
01000     Created:    16/11/94
01001     Returns:    DocRect - Returns the bounding rect of the shape and its blobs
01002     Purpose:    This calculates the bounding box of the shape's path and adds in the
01003                 influence of the selection blobs. It does not consider if the blobs are
01004                 visible or not, it just gives the bounding box that they would occupy if
01005                 they were visible
01006 
01007 ********************************************************************************************/
01008 DocRect NodeRegularShape::GetBlobBoundingRect()
01009 {
01010     // Find the Shapes bounding rectangle
01011     DocRect Rect = GetBoundingRect();
01012 
01013     Path* RenderPath = NULL;
01014     BuildShapePath(&RenderPath);
01015 
01016     // Add on the sizes of the blobs
01017     BlobManager* pBlobMgr = GetApplication()->GetBlobManager();
01018     if (pBlobMgr!= NULL)
01019     {
01020         DocRect BlobSize;
01021         // There is a tiny blob on the MoveTo point
01022         DocCoord* Coords = RenderPath->GetCoordArray();
01023         pBlobMgr->GetBlobRect(Coords[0], &BlobSize);
01024         Rect = Rect.Union(BlobSize);
01025 
01026         // And a blob on the centre point
01027         DocCoord Point = GetCentrePoint();
01028         pBlobMgr->GetBlobRect(Point, &BlobSize);
01029         Rect = Rect.Union(BlobSize);
01030     }
01031 
01032     // Now include the blobs at the primary and stellation points, and their curvature points.
01033     if (!IsCircular())
01034     {
01035         DocCoord*   Array;
01036         INT32 Points = 0;
01037         BOOL Success = BuildPolygonPoints(&Array, &Points);
01038         UINT32 Counter = 0;
01039         if (Success)
01040         {
01041             TransformMatrix.transform((Coord*)Array, Points);
01042             DocRect BlobSize;
01043             for (UINT32 loop = 0; loop < NumSides; loop++)
01044             {
01045                 if (IsStellated())
01046                 {
01047                     if (IsStellationCurvature())
01048                     {
01049                         pBlobMgr->GetBlobRect(Array[Counter], &BlobSize);
01050                         Rect = Rect.Union(BlobSize);
01051                         pBlobMgr->GetBlobRect(Array[Counter+1], &BlobSize);
01052                         Rect = Rect.Union(BlobSize);
01053                         pBlobMgr->GetBlobRect(Array[Counter+2], &BlobSize);
01054                         Rect = Rect.Union(BlobSize);
01055                         Counter += 3;
01056                     }           
01057                     else
01058                     {
01059                         pBlobMgr->GetBlobRect(Array[Counter++], &BlobSize);
01060                         Rect = Rect.Union(BlobSize);
01061                     }
01062                 }
01063 
01064                 if (IsPrimaryCurvature())
01065                 {
01066                     pBlobMgr->GetBlobRect(Array[Counter], &BlobSize);
01067                     Rect = Rect.Union(BlobSize);
01068                     pBlobMgr->GetBlobRect(Array[Counter+1], &BlobSize);
01069                     Rect = Rect.Union(BlobSize);
01070                     pBlobMgr->GetBlobRect(Array[Counter+2], &BlobSize);
01071                     Rect = Rect.Union(BlobSize);
01072                     Counter += 3;
01073                 }
01074                 else
01075                 {
01076                     pBlobMgr->GetBlobRect(Array[Counter++], &BlobSize);
01077                     Rect = Rect.Union(BlobSize);
01078                 }
01079             }
01080         }
01081         if (Array != NULL)
01082             delete [] Array;
01083     }
01084     else
01085     {
01086         DocRect BlobSize;
01087         DocCoord Point = GetMajorAxes();
01088         pBlobMgr->GetBlobRect(Point, &BlobSize);
01089         Rect = Rect.Union(BlobSize);
01090         DocCoord Opposite = GetCentrePoint() - (GetMajorAxes() - GetCentrePoint());
01091         pBlobMgr->GetBlobRect(Opposite, &BlobSize);
01092         Rect = Rect.Union(BlobSize);
01093         Point = GetMinorAxes();
01094         pBlobMgr->GetBlobRect(Point, &BlobSize);
01095         Rect = Rect.Union(BlobSize);
01096         Opposite = GetCentrePoint() - (GetMinorAxes() - GetCentrePoint());
01097         pBlobMgr->GetBlobRect(Opposite, &BlobSize);
01098         Rect = Rect.Union(BlobSize);
01099     }
01100 
01101     // Make sure we include the Bounds of our children
01102     IncludeChildrensBoundingRects(&Rect);
01103 
01104     // return the rectangle with the blobs included
01105     return Rect;
01106 }
01107 
01108 
01109 
01110 /********************************************************************************************
01111 
01112 >   virtual UINT32 NodeRegularShape::GetNodeSize() const
01113 
01114     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
01115     Created:    16/11/94
01116     Returns:    The size of the node in bytes 
01117     Purpose:    For finding the size of the node 
01118     SeeAlso:    Node::GetSubtreeSize
01119 
01120 ********************************************************************************************/
01121 UINT32 NodeRegularShape::GetNodeSize() const 
01122 {     
01123     return (sizeof(NodeRegularShape)); 
01124 }  
01125 
01126 
01127 
01128 /********************************************************************************************
01129 
01130 >   BOOL NodeRegularShape::OnClick( DocCoord PointerPos, ClickType Click, ClickModifiers ClickMods,
01131                                                 Spread* pSpread)
01132 
01133     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
01134     Created:    16/11/94
01135     Inputs:     PointerPos - The Location of the mouse pointer at the time of the click
01136                 Click - The type of click received (single, double, drag etc)
01137                 ClickMods - The modifiers to the click (eg shift, control etc )
01138     Returns:    BOOL - TRUE if the node claims the click as its own and FALSE if it is
01139                 not interested in the click
01140     Purpose:    Allows the QuickShape to respond to clicks by selecting its blobs or starting
01141                 drags etc.
01142 
01143 ********************************************************************************************/
01144 
01145 BOOL NodeRegularShape::OnClick( DocCoord PointerPos, ClickType Click, ClickModifiers ClickMods,
01146                                                         Spread* pSpread)
01147 {
01148 #ifndef STANDALONE
01149 
01150     // we only handle the click if we can confirm that object blobs are being displayed.
01151     BlobManager* pBlobMgr = GetApplication()->GetBlobManager();
01152     if (pBlobMgr == NULL)
01153         return FALSE;
01154     if (!pBlobMgr->GetCurrentInterest().Object)
01155         return FALSE;
01156 
01157     DocCoord Start;
01158     DocCoord End;
01159     INT32 DragPointNumber;
01160     ShapeClickEffect HitTest = DetermineClickEffect(&PointerPos, pSpread, &DragPointNumber, &Start, &End);
01161     switch (HitTest)
01162     {
01163         case SHAPECLICK_CENTRE:
01164         {
01165             return ClickCentre(PointerPos, Click, ClickMods, pSpread);
01166             break;
01167         }
01168         case SHAPECLICK_ELLIPSE:
01169         {
01170             return ClickEllipse(PointerPos, Click, ClickMods, pSpread, FALSE);
01171             break;
01172         }
01173         case SHAPECLICK_PRIMARY:
01174         {
01175             return ClickPrimary(PointerPos, Click, ClickMods, pSpread, TRUE);
01176             break;
01177         }
01178         case SHAPECLICK_RECTANGLE:
01179         {
01180             return ClickPrimary(PointerPos, Click, ClickMods, pSpread, FALSE);
01181             break;
01182         }
01183         case SHAPECLICK_STELLATION:
01184         {
01185             return ClickStellation(PointerPos, Click, ClickMods, pSpread);
01186             break;
01187         }
01188         case SHAPECLICK_PRIMARYCURVE:
01189         {
01190             return ClickPCurve(PointerPos, Click, ClickMods, pSpread, Start, End);
01191             break;
01192         }
01193         case SHAPECLICK_STELLATIONCURVE:
01194         {
01195             return ClickSCurve(PointerPos, Click, ClickMods, pSpread, Start, End);
01196             break;
01197         }
01198         default: break;
01199     }
01200 
01201 #endif
01202 
01203     // did not use the click
01204     return FALSE;
01205 }
01206 
01207 
01208 
01209 /********************************************************************************************
01210 
01211 >   BOOL NodeRegularShape::OnToolClick( DocCoord PointerPos, ClickType Click, ClickModifiers ClickMods,
01212                                                 Spread* pSpread)
01213 
01214     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
01215     Created:    25/5/95
01216     Inputs:     PointerPos - The Location of the mouse pointer at the time of the click
01217                 Click - The type of click received (single, double, drag etc)
01218                 ClickMods - The modifiers to the click (eg shift, control etc )
01219     Returns:    BOOL - TRUE if the node claims the click as its own and FALSE if it is
01220                 not interested in the click
01221     Purpose:    Allows the QuickShape to respond to clicks by selecting its blobs or starting
01222                 drags etc.  This function is the same as OnClick execpt it is called from the
01223                 QuickShape tool.  It does QuickShape dragging on rectangles and ellipses
01224                 (instead of the specialised rect/ellipse drag).  It also allows edge reforming
01225 
01226 ********************************************************************************************/
01227 
01228 BOOL NodeRegularShape::OnToolClick( DocCoord PointerPos, ClickType Click, ClickModifiers ClickMods,
01229                                                         Spread* pSpread)
01230 {
01231 #ifndef STANDALONE
01232 
01233     // Call the default handler for all tools
01234     BOOL ClickUsed = OnClick(PointerPos, Click, ClickMods, pSpread);
01235 
01236     // Now test for special operations only supplied by shape editing tools
01237     if (!ClickUsed)
01238     {
01239         DocCoord Start;
01240         DocCoord End;
01241         INT32 DragPointNumber;
01242         ShapeClickEffect HitTest = DetermineClickEffect(&PointerPos, pSpread, &DragPointNumber, &Start, &End);
01243 
01244         if (HitTest==SHAPECLICK_EDGE1 || HitTest==SHAPECLICK_EDGE2)
01245             return ClickEdge(PointerPos, Click, ClickMods, pSpread, (HitTest==SHAPECLICK_EDGE1) );
01246     }
01247 
01248 #endif
01249 
01250     // did not use the click
01251     return FALSE;
01252 }
01253 
01254 
01255 
01256 /********************************************************************************************
01257 
01258 >   virtual BOOL NodeRegularShape::CanBecomeA(BecomeA* pBecomeA)
01259 
01260     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
01261     Created:    16/11/94
01262     Inputs:     InkClass: The class of object
01263                 pNumObjects = ptr to place number of objects of type pClass that will be created (Note: can be NULL).
01264                               *pNumObects in undefined on entry
01265     Returns:    TRUE if the node, or any of its children can transmogrify themselves to become 
01266                 an InkClass object
01267     Purpose:    This function is used by the convert to shapes operation. It determines if 
01268                 the node or any of its children can convert themselves into an InkClass object. 
01269 
01270                 The number you put into pNumObjects (if it's not NULL) should exactly equal the total number
01271                 of pClass objects you create.  It should NOT contain any additional objects you may produce
01272                 such as group objects for containing the pClass object, or attributes.
01273 
01274                 Also, the entry value of *pNumObjects cannot be assumed to be 0.
01275 
01276 ********************************************************************************************/
01277 
01278 BOOL NodeRegularShape::CanBecomeA(BecomeA* pBecomeA)
01279 {
01280     // The NodeRegularShape can become a NodePath
01281     if (pBecomeA->BAPath())
01282     {
01283         pBecomeA->AddCount(1);
01284 
01285         return TRUE;
01286     }
01287 
01288     return FALSE;
01289 }
01290 
01291 
01292            
01293 /********************************************************************************************
01294 
01295 >   virtual BOOL NodeRegularShape::DoBecomeA(BecomeA* pBecomeA) 
01296 
01297     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
01298     Created:    25/11/94
01299     Inputs:     pBecomeA =  ptr to a class that contains all the info needed to become a new
01300                             type of node.
01301     Outputs:    -
01302     Returns:    TRUE if the object has been transformed, FALSE if we run out of memory
01303     Purpose:    Transforms the object into another type of object. 
01304     SeeAlso:    NodeRegularShape::CanBecomeA
01305 
01306 ********************************************************************************************/
01307 
01308 BOOL NodeRegularShape::DoBecomeA(BecomeA* pBecomeA)
01309 {
01310     // Check for a NULL entry param                            
01311     ERROR2IF_PF(pBecomeA == NULL,FALSE,("pBecomeA is NULL"));
01312 
01313     // This lump checks that the Reason is one that we understand
01314     // It also makes sure that we don't have a NULL UndoOp ptr
01315     BOOL ValidReason = (pBecomeA->GetReason() == BECOMEA_REPLACE || pBecomeA->GetReason() == BECOMEA_PASSBACK);
01316     ERROR2IF_PF(!ValidReason,FALSE,("Unkown BecomeA reason %d",pBecomeA->GetReason()));
01317 
01318     // pBecomeA->Reason is one that we understand.
01319     BOOL        Success = TRUE;         // Our success flag (Important that this defaults to TRUE)
01320     NodePath*   pNewNodePath = NULL;    // Ptr to a new NodePath, if we get to make one.
01321 
01322     if (pBecomeA->BAPath())
01323     {
01324         // We need to create a new NodePath, no matter what the reason.
01325 
01326         // Allocate a new NodePath node
01327         ALLOC_WITH_FAIL(pNewNodePath, (new NodePath), pBecomeA->GetUndoOp()); 
01328         Success = (pNewNodePath != NULL);
01329 
01330         // Get the shapes render path into the node path.
01331         Path* ShapePath = NULL;
01332         if (Success)
01333             Success = BuildShapePath(&ShapePath);
01334         pNewNodePath->InkPath.Initialise(ShapePath->GetNumCoords(),1);
01335     
01336         if (Success) CALL_WITH_FAIL(pNewNodePath->InkPath.CopyPathDataFrom(ShapePath), pBecomeA->GetUndoOp(), Success);
01337     
01338 
01339         // If Success is TRUE, then we now have a new NodePath object that contains this shape's path
01340         if (Success)
01341         {
01342             switch (pBecomeA->GetReason())
01343             {
01344                 case BECOMEA_REPLACE :
01345                 {
01346                     // It's a BECOMEA_REPLACE, so replace this node with the new NodePath
01347                     UndoableOperation* pOp = pBecomeA->GetUndoOp();
01348 
01349                     // Firstly, hide this node
01350                     NodeHidden* pNodeHidden = NULL; 
01351                     if (pOp != NULL)
01352                         Success = pBecomeA->GetUndoOp()->DoHideNode(this, TRUE, &pNodeHidden);
01353 
01354                     if (Success)
01355                     {
01356                         // Insert the new NodePath into the tree, next to the hidden node
01357                         if (pOp != NULL)
01358                             pNewNodePath->AttachNode(pNodeHidden,NEXT);
01359                         else
01360                             pNewNodePath->AttachNode(this,NEXT);
01361 
01362                         // Copy the node's attributes
01363                         CALL_WITH_FAIL(CopyChildrenTo(pNewNodePath), pBecomeA->GetUndoOp(), Success); 
01364 
01365                         if (Success)
01366                         {
01367                             // Set the bounds  
01368                             pNewNodePath->InvalidateBoundingRect();
01369                             pNewNodePath->SetSelected(IsSelected());
01370 
01371                             // Create a hide node action to hide the node when we undo 
01372                             if (pOp != NULL)
01373                             {
01374                                 HideNodeAction* UndoHideNodeAction;     
01375                                 Success = (HideNodeAction::Init(pBecomeA->GetUndoOp(),
01376                                                          pBecomeA->GetUndoOp()->GetUndoActionList(),
01377                                                          pNewNodePath, 
01378                                                          TRUE,       // Include subtree size 
01379                                                          ( Action**)(&UndoHideNodeAction))
01380                                                          != AC_FAIL);
01381                             }
01382                             else
01383                             {
01384                                 UnlinkNodeFromTree();
01385                                 CascadeDelete();    // Delete all of the children
01386                                 delete this;        // SCARY!
01387                                 return TRUE; 
01388                             }
01389                         }
01390                     }
01391 
01392                     if (Success)
01393                         pBecomeA->PassBack(pNewNodePath,this);
01394                 }
01395                 break;
01396 
01397                 case BECOMEA_PASSBACK :
01398                     Success = pBecomeA->PassBack(pNewNodePath,this);
01399                 break;
01400 
01401                 default: break;
01402             }
01403         }
01404     }
01405 
01406     if (!Success)
01407     {
01408         if (pNewNodePath != NULL)
01409         {
01410             // Delete all the NodePath's children (if it has any) and unlink it from the tree (if it's linked)
01411             // This is all done by CascadeDelete()
01412             pNewNodePath->CascadeDelete(); 
01413             delete pNewNodePath;
01414             pNewNodePath = NULL;
01415         }
01416     }
01417 
01418     return Success;
01419 }
01420 
01421 
01422 /***********************************************************************************************
01423 >   virtual NodePath* NodeRegularShape::GetVariableWidthStrokePath()
01424     
01425     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01426     Created:    15-5-2000
01427     Inputs:     -  
01428     Outputs:    -
01429     Returns:    a nodepath containing the path that is generated by any variable width strokes that
01430                 are applied to us, or NULL if there aren't any
01431     Purpose:    If we have a variable width stroke applied to us then this will get the path generated
01432                 by that stroke.  This base class version returns NULL, overridden versions must supply
01433                 their own outline path.
01434 
01435                 In this version we provide our own path by using BuildShapePath
01436 
01437     See also:   NodePath::GetVariableWidthStrokePath, NodeRegularShape::GetVariableWidthStrokePath
01438                 
01439     
01440 ***********************************************************************************************/
01441 
01442 NodePath* NodeRegularShape::GetVariableWidthStrokePath()
01443 {
01444     // first find out if we actually have a variable width applied to us, if not then we don't do anything
01445     AttrVariableWidth* pVarWidth = NULL;
01446     FindAppliedAttribute(CC_RUNTIME_CLASS(AttrVariableWidth), (NodeAttribute**)&pVarWidth);
01447     if (pVarWidth == NULL || ((VariableWidthAttrValue*)pVarWidth->GetAttributeValue())->GetWidthFunction() == NULL)
01448         return NULL;
01449 
01450     // next find the stroke attribute that actually does the work
01451     AttrStrokeType* pStroke = NULL;
01452     FindAppliedAttribute(CC_RUNTIME_CLASS(AttrStrokeType), (NodeAttribute**)&pStroke);
01453     
01454     NodePath* pRetNode = NULL;
01455     if (pStroke && pStroke->HasPathProcessor())
01456     {
01457         PathProcessorStroke* pPPS = pStroke->GetPathProcessor();
01458             
01459         // Get the shapes render path 
01460         Path* pShapePath = NULL;
01461         if (BuildShapePath(&pShapePath))
01462             pRetNode = pPPS->GetProcessedPath(pShapePath, this);
01463 
01464         ERROR2IF(!pRetNode, NULL, "Failed to get a Processed Path");
01465                 
01466         // now we have a choice, pass in the stroking flag to produce a path that works with bevels
01467         Path CopyPath;
01468         CopyPath.Initialise();
01469         CopyPath.CloneFrom(pRetNode->InkPath);
01470 
01471         // Mark Howitt 31/10/00
01472         // I`ve removed the ClipPathToPathWithAutoFlatness function and replaced it with
01473         // the function that returns you a flatness value to use with the ClipPath function
01474         double ClippingFlatness = CopyPath.CalculateFlatnessValueFromPath(2.0, 375.0, 500.0);
01475         double SourceFlatness = pShapePath->CalculateFlatnessValueFromPath(2.0, 375.0, 500.0);
01476 
01477         CopyPath.ClipPathToPath(*pShapePath, &(pRetNode->InkPath), 7, 1, ClippingFlatness, SourceFlatness);
01478 
01479         pRetNode->InkPath.InitialiseFlags();
01480         // lets have a go at smoothing it
01481         Spread *pSpread = Document::GetSelectedSpread();
01482 
01483         //Smoothness value is important - too little smoothness and you'll still have an over-complicated
01484         //path - too much and you'll lose detail...
01485         double smoothness = 15.0;
01486             
01487         //Use the retro smoother on all points without rendering to screen the EOR'd version...
01488         RetroSmooth rSmoother;
01489         rSmoother.Initialise();
01490         rSmoother.SetRenderFlag(false);
01491 
01492         // smooth the new path
01493         pRetNode->InkPath.SetAllSubSelection();
01494         rSmoother.Changing(pRetNode, pSpread, smoothness);
01495         rSmoother.FinishedNoUndo(pRetNode);
01496         pRetNode->InkPath.ClearSubSelection();
01497         
01498     }
01499         
01500     return pRetNode;    
01501 }
01502 
01503 
01504 
01505 /***********************************************************************************************
01506 >   virtual NodePath* NodeRegularShape::GetSmoothVariableWidthStrokePath()
01507     
01508     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01509     Created:    15-5-2000
01510     Inputs:     -  
01511     Outputs:    -
01512     Returns:    a nodepath containing the path that is generated by any variable width strokes that
01513                 are applied to us, or NULL if there aren't any
01514     Purpose:    If we have a variable width stroke applied to us then this will get the path generated
01515                 by that stroke.  This base class version returns NULL, overridden versions must supply
01516                 their own outline path.
01517 
01518                 In this version we provide our own path by using BuildShapePath
01519 
01520     See also:   NodePath::GetVariableWidthStrokePath, NodeRegularShape::GetVariableWidthStrokePath
01521                 
01522     
01523 ***********************************************************************************************/
01524 
01525 NodePath* NodeRegularShape::GetSmoothVariableWidthStrokePath()
01526 {
01527     // first find out if we actually have a variable width applied to us, if not then we don't do anything
01528     AttrVariableWidth* pVarWidth = NULL;
01529     FindAppliedAttribute(CC_RUNTIME_CLASS(AttrVariableWidth), (NodeAttribute**)&pVarWidth);
01530     if (pVarWidth == NULL || ((VariableWidthAttrValue*)pVarWidth->GetAttributeValue())->GetWidthFunction() == NULL)
01531         return NULL;
01532 
01533     // next find the stroke attribute that actually does the work
01534     AttrStrokeType* pStroke = NULL;
01535     FindAppliedAttribute(CC_RUNTIME_CLASS(AttrStrokeType), (NodeAttribute**)&pStroke);
01536     
01537     NodePath* pRetNode = NULL;
01538     if (pStroke && pStroke->HasPathProcessor())
01539     {
01540         PathProcessorStroke* pPPS = pStroke->GetPathProcessor();
01541             
01542         // Get the shapes render path 
01543         Path* pShapePath = NULL;
01544         if (BuildShapePath(&pShapePath))
01545             pRetNode = pPPS->GetSmoothProcessedPath(pShapePath, this);
01546                 
01547         // now we have a choice, pass in the stroking flag to produce a path that works with bevels
01548         Path CopyPath;
01549         CopyPath.Initialise();
01550         CopyPath.CloneFrom(pRetNode->InkPath);
01551 
01552         // Mark Howitt 31/10/00
01553         // I`ve removed the ClipPathToPathWithAutoFlatness function and replaced it with
01554         // the function that returns you a flatness value to use with the ClipPath function
01555         double ClippingFlatness = CopyPath.CalculateFlatnessValueFromPath(2.0, 375.0, 500.0);
01556         double SourceFlatness = pShapePath->CalculateFlatnessValueFromPath(2.0, 375.0, 500.0);
01557 
01558         CopyPath.ClipPathToPath(*pShapePath, &(pRetNode->InkPath), 7, 1, ClippingFlatness, SourceFlatness);
01559 
01560         pRetNode->InkPath.InitialiseFlags();
01561     }
01562         
01563     return pRetNode;    
01564 }
01565 
01566 
01567 
01568 
01569 
01570 /***********************************************************************************************
01571 
01572 > BOOL NodeRegularShape::Snap(DocCoord* pDocCoord)
01573 
01574     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
01575     Created:    21/12/94
01576     Inputs:     pDocCoord   = a coord in Spread coords
01577     Outputs:    If the point is snapped then pDocCoord will contain the point of attraction.
01578     Returns:    TRUE    - the DocCoord has been snapped to the shapes path.
01579                 FALSE   - the DocCoord has not been processed.
01580                                                          
01581     Purpose:    Snaps to given coord to the nearest point on the shapes render path.  If it is
01582                 not appropriate to snap the coord to the shape (at the moment this means the
01583                 coord is too far awawy), then FALSE is returned.
01584     Errors:     -   
01585     Scope:      public
01586            
01587 **********************************************************************************************/
01588 
01589 BOOL NodeRegularShape::Snap(DocCoord* pDocCoord)
01590 {
01591 #if !defined(EXCLUDE_FROM_RALPH)
01592     Path* RenderPath = NULL;
01593     BOOL Snapped = FALSE;
01594     if (BuildShapePath(&RenderPath))
01595         Snapped = CSnap::SnapCoordToPath(pDocCoord, RenderPath);
01596 
01597     return Snapped;
01598 #else
01599     return FALSE;
01600 #endif
01601 }
01602 
01603 
01604 /***********************************************************************************************
01605 
01606 > BOOL NodeRegularShape::Snap(DocRect* pDocRect,const DocCoord& PrevCoord,const DocCoord& CurCoord)
01607 
01608     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01609     Created:    21/9/94
01610     Inputs:     pDocCoord   - the rectangle to snap
01611                 StartDrag   - Start coord of drag
01612                 EndDrag     - End coord of drag
01613     Outputs:    
01614     Returns:    TRUE    - the DocRect been snapped to the grid.
01615                 FALSE   - the DocRect has not been processed.
01616                                                          
01617     Purpose:    Snaps the given rect to the nearest position on the grid, preserving its width
01618                 and height.
01619                 The coords of the rect used for the snapping are determined by the PrevCoord and
01620                 CurCoord coords supplied.  This is done to allow the user to control how a
01621                 selection rectangle is snapped to the grid by the direction of his/her last mouse 
01622                 movement.
01623                 To force the bottom left hand corner of the rect to be snapped, 
01624                 supply PrevCoord=(0,0) and CurCoord(-1,-1).
01625     Scope:      public
01626            
01627 **********************************************************************************************/
01628 
01629 BOOL NodeRegularShape::Snap(DocRect* pDocRect,const DocCoord& PrevCoord,const DocCoord& CurCoord)
01630 {
01631     return FALSE;
01632 }
01633 
01634 
01635 
01636 /********************************************************************************************
01637 
01638 >   BOOL NodeRegularShape::SnapToCoords(DocCoord* pDocCoord)
01639 
01640     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
01641     Created:    29/3/95
01642     Inputs:     pDocCoord - the coord to try and snap to
01643     Outputs:    pDocCoord - The snapped coord, if it was close enough to any of the magnetic
01644                 points for a rectangle.
01645     Returns:    TRUE if it was snapped, FALSE if not
01646     Purpose:    Snaps the point magnetically to the the significant points of the shape
01647 
01648 ********************************************************************************************/
01649 
01650 BOOL NodeRegularShape::SnapToCoords(DocCoord* pDocCoord)
01651 {
01652 #if !defined(EXCLUDE_FROM_RALPH)
01653     BOOL IsSnapped = FALSE;
01654     
01655     // We can try snapping to the objects centre point
01656     DocCoord Centre=GetCentrePoint();
01657     if (IsMagneticallyClose(&Centre, pDocCoord))
01658         IsSnapped = TRUE;
01659 
01660     // Try the significant points
01661     if (!IsSnapped)
01662     {
01663         if (IsCircular())
01664         {
01665             DocCoord Points[4];
01666             Points[0]=GetMinorAxes();
01667             Points[1]=GetMajorAxes();
01668             Points[2]=GetCentrePoint() - (GetMajorAxes() - GetCentrePoint());
01669             Points[3]=GetCentrePoint() - (GetMinorAxes() - GetCentrePoint());
01670 
01671             for (INT32 loop = 0; (!IsSnapped && (loop<4)); loop++)
01672                 IsSnapped = IsMagneticallyClose(&(Points[loop]), pDocCoord);
01673         }
01674         else
01675         {
01676             DocCoord* Array = NULL;
01677             INT32 Points = 0;
01678             if (BuildPolygonPoints(&Array, &Points))
01679             {
01680                 TransformMatrix.transform((Coord*)Array, Points);
01681                 for (INT32 loop = 0; ((loop < Points) && !IsSnapped); loop++)
01682                 {
01683                     if (IsMagneticallyClose(&(Array[loop]), pDocCoord))
01684                         IsSnapped = TRUE;
01685                 }
01686 
01687                 // Rectangle special case - snap half way between each vertex
01688                 if (IsARectangle() && !IsReformed())
01689                 {
01690                     for (INT32 loop = 1; ((loop < Points) && !IsSnapped); loop++)
01691                     {
01692                         DocCoord MidPoint( (Array[loop-1].x+Array[loop].x)/2, (Array[loop-1].y+Array[loop].y)/2 );
01693                         if (IsMagneticallyClose(&MidPoint, pDocCoord))
01694                             IsSnapped = TRUE;
01695                     }
01696                 }
01697             }
01698             if (Array != NULL)
01699                 delete [] Array;
01700         }
01701     }
01702     else
01703     {
01704     }
01705 
01706     return IsSnapped;
01707 #else
01708     return FALSE;
01709 #endif
01710 }
01711 
01712 
01713 
01714 /********************************************************************************************
01715 
01716 >   virtual String NodeRegularShape::Describe(BOOL Plural, BOOL Verbose = TRUE)
01717 
01718     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
01719     Created:    22/11/94
01720     Inputs:     Plural: Flag indicating if the string description should be plural or
01721                 singular. 
01722     Returns:    Description of the object                                    
01723     Purpose:    To return a description of the NodeRegularShape object in either the singular
01724                 or the plural. This method is called by the DescribeRange method.
01725                 The description will always begin with a lower case letter.   
01726     Errors:     A resource exception will be thrown if a problem occurs when loading the 
01727                 string resource. 
01728 
01729 ********************************************************************************************/
01730               
01731 String NodeRegularShape::Describe(BOOL Plural, BOOL Verbose) 
01732 {     
01733     // Are we a circle?
01734     if (IsCircular())
01735     {
01736         if (Plural)
01737             return(String(_R(IDS_ELLIPSE_DESCRP)));  
01738         else
01739             return(String(_R(IDS_ELLIPSE_DESCRS))); 
01740     }
01741 
01742     // Are we a rectangle?
01743     if (IsARectangle())
01744     {
01745         if (Plural)
01746             return(String(_R(IDS_RECTANGLE_DESCRP)));  
01747         else
01748             return(String(_R(IDS_RECTANGLE_DESCRS))); 
01749     }
01750     
01751     // OK, we are a boring old QuickShape
01752     if (Plural)
01753         return(String(_R(IDS_REGSHAPE_PLURAL)));  
01754     else
01755         return(String(_R(IDS_REGSHAPE_SINGULAR))); 
01756 }; 
01757 
01758 
01759 
01760 /********************************************************************************************
01761 
01762 >   void NodeRegularShape::PositionPointFromRatio(DocCoord* PosPoint, DocCoord* EndPoint, double Ratio)
01763 
01764     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
01765     Created:    30/11/94
01766     Inputs:     PosPoint - pointer to a DocCoord to change.
01767                 EndPoint - pointer to a DocCoord at the end of a line from the CentrePoint
01768                 Ratio - the distance along the line to set PosPoint.  0 sets it at CentrePoint,
01769                 1 sets it at EndPoint.
01770     Outputs:    Stores the location of the point in PosPoint.
01771     Returns:    -                                   
01772     Purpose:    To obtain the position of a point at any position along any line from the
01773                 (Untransformed) CentrePoint of the Regular shape.
01774     Errors:     -
01775 
01776 ********************************************************************************************/
01777 void NodeRegularShape::PositionPointFromRatio(DocCoord* PosPoint, const DocCoord* EndPoint, const double Ratio)
01778 {
01779     PosPoint->x = UTCentrePoint.x + (INT32)((EndPoint->x - UTCentrePoint.x)*Ratio) ;
01780     PosPoint->y = UTCentrePoint.y + (INT32)((EndPoint->y - UTCentrePoint.y)*Ratio) ;
01781 } 
01782 
01783 
01784 
01785 /********************************************************************************************
01786 
01787 >   BOOL NodeRegularShape::MakeRegular(DocCoord RegularPoint)
01788 
01789     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
01790     Created:    13/12/94
01791     Inputs:     RegularPoint - the DocCoord defining the regularness ofthe shape
01792     Outputs:    -
01793     Returns:    FALSE if error occured 
01794     Purpose:    To make a shape regular, 1:1 aspect ratio
01795     Errors:     -
01796 
01797 ********************************************************************************************/
01798 BOOL NodeRegularShape::MakeRegular(DocCoord RegularPoint)
01799 {
01800 #ifndef STANDALONE
01801 
01802     ERROR3IF(NumSides < REGULARSHAPE_MINSIDES, "Shape not inited!");
01803 
01804     OpShapeMakeRegular* Apple = new OpShapeMakeRegular;
01805     if (Apple != NULL)
01806     {
01807         Apple->DoMakeRegular(this, RegularPoint);
01808         return TRUE;
01809     }
01810     else
01811         return FALSE;
01812 #else
01813     return FALSE;
01814 #endif
01815 } 
01816 
01817 
01818 
01819 /********************************************************************************************
01820 
01821 >   BOOL NodeRegularShape::MakeStraight(BOOL StraightenOne)
01822 
01823     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
01824     Created:    10/1/95
01825     Inputs:     StraightenOne TRUE if EdgePath1 should be made a line, FALSE to straighten EdgePath2.
01826     Outputs:    Either EdgePath1 or EdgePath2 will have been made a straight line.
01827     Returns:    FALSE if error occured (SetError will have been called)                                   
01828     Purpose:    Call this function to reset a shapes edge path back to a straight line.  An
01829                 OpEditRegularShape is created to carry out the change.  
01830     Errors:     Will complain if it runs out of memory
01831 
01832 ********************************************************************************************/
01833 BOOL NodeRegularShape::MakeStraight(BOOL StraightenOne)
01834 {
01835 #ifndef STANDALONE
01836 
01837     ERROR3IF(NumSides < REGULARSHAPE_MINSIDES, "Shape not inited!");
01838 
01839     EditRegularShapeParam ChangeData(this);
01840     Path NewEdge;
01841 
01842     // Create the straight path 
01843     if (NewEdge.Initialise(4, 1))
01844     {
01845         DocCoord Fred1(0,0);
01846         DocCoord Fred2(72000,0);
01847         NewEdge.SetPathPosition(0);
01848         NewEdge.AddMoveTo(Fred1);
01849         NewEdge.AddCurveTo(Fred2);
01850     }
01851     else
01852     {
01853         Error::SetError(_R(IDS_OUT_OF_MEMORY));
01854         return FALSE;
01855     }
01856 
01857     if (StraightenOne)
01858         ChangeData.NewEdgePath1 = &NewEdge;
01859     else
01860         ChangeData.NewEdgePath2 = &NewEdge;
01861 
01862     // Now do the operation
01863     OpDescriptor* Apple = OpDescriptor::FindOpDescriptor(CC_RUNTIME_CLASS(OpEditRegularShape));
01864     if (Apple != NULL)  
01865     {
01866         Apple->Invoke(&ChangeData);
01867         return TRUE;
01868     }
01869     else
01870     {
01871         Error::SetError(_R(IDS_OUT_OF_MEMORY));
01872         return FALSE;
01873     }
01874 #else
01875     return TRUE;
01876 #endif
01877 } 
01878 
01879 
01880 
01881 /*******************************************************************************************
01882 
01883 > ShapeClickEffect NodeRegularShape::DetermineClickEffect(  DocCoord* pPos,
01884                                                             Spread* pSpread,
01885                                                             INT32* pPointNum, 
01886                                                             DocCoord* pStart = NULL,
01887                                                             DocCoord* pEnd = NULL)
01888     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
01889     Created:    12/12/94
01890     Inputs:     pPos is the position to test
01891                 pSpread is a pointer to the spread containing the position
01892                 pPointNum, pStart and pEnd are return pointers
01893     Outputs:    pPos is adjusted to the point on the shape that was clicked on eg, a point
01894                 near the centre point returns SHAPECLICK_CENTRE and pPos will be set to the
01895                 centre point of the shape.
01896                 pPointNum is the significant point number if the hit point, -1 if it isn't 
01897                 numbered (eg centre point)
01898                 pStart points to the start of the edge that contains the hit object
01899                 pEnd points to the end of the edge that contains the hit object
01900                 NOTE: These two are only set if the hit object is a curvature blob!
01901     Returns:    The effect of clicking - one of NewShape, OnCentre, OnMajorPoint, etc...
01902     Purpose:    Used when the cursor moves and when single clicking. This routine determines
01903                 what effect a click will have by looking at the object under the pointer.
01904 
01905 ********************************************************************************************/
01906 
01907 ShapeClickEffect NodeRegularShape::DetermineClickEffect(DocCoord* pPos, Spread* pSpread,
01908                                                 INT32* pPointNum, DocCoord* pStart, DocCoord* pEnd)
01909 {
01910 #ifndef STANDALONE
01911 
01912     // Only get excited if the object is on the same spread as the pointer.
01913     if (FindParentSpread() != pSpread)
01914         return SHAPECLICK_NONE;
01915 
01916     DocRect BlobBounds;
01917     DocCoord Interest;
01918     *pPointNum = -1;
01919 
01920     // Are we over any of the polygon object blobs?
01921     // Now draw blobs at the primary and stellation points, and their curvature points.
01922     if (!IsCircular())
01923     {
01924         DocCoord*   Array;
01925         INT32 Points = 0;
01926         BOOL Success = BuildPolygonPoints(&Array, &Points);
01927         UINT32 Counter = 0;
01928         ShapeClickEffect TempEffect = SHAPECLICK_NONE;
01929         if (Success)
01930         {
01931             TransformMatrix.transform((Coord*)Array,Points);
01932             for (UINT32 loop = 0; loop < NumSides; loop++)
01933             {
01934                 UINT32 EndOffset = 1;
01935                 DocCoord Start = Array[Counter];
01936                 DocCoord StellEnd(0,0);
01937                 DocCoord PrimeEnd;
01938                 if (IsPrimaryCurvature())
01939                     EndOffset++ ;
01940                 if (IsStellated())
01941                 {
01942                     if (IsStellationCurvature())
01943                         EndOffset++;
01944                     StellEnd = Array[Counter + EndOffset];
01945                     EndOffset++;
01946                     if (IsStellationCurvature())
01947                         EndOffset++;
01948                 }
01949                 if (IsPrimaryCurvature())
01950                     EndOffset++ ;
01951                 PrimeEnd = Array[Counter + EndOffset];
01952             
01953                 GetApplication()->GetBlobManager()->GetBlobRect(Array[Counter++],&BlobBounds);
01954                 if (BlobBounds.ContainsCoord(*pPos))
01955                 {
01956                     TempEffect = SHAPECLICK_PRIMARY;
01957                     *pPos = Array[Counter-1];
01958                     *pPointNum = Counter-1;
01959                     goto FoundBlob;
01960                 }
01961 
01962                 if (IsPrimaryCurvature())
01963                 {
01964                     GetApplication()->GetBlobManager()->GetBlobRect(Array[Counter++],&BlobBounds);
01965                     if (BlobBounds.ContainsCoord(*pPos))
01966                     {
01967                         *pPos = Array[Counter-1];
01968                         *pPointNum = Counter-1;
01969                         if (pStart != NULL)
01970                             *pStart = Start;
01971                         if (pEnd != NULL)
01972                         {
01973                             if (IsStellated())
01974                                 *pEnd = StellEnd;
01975                             else
01976                                 *pEnd = PrimeEnd;
01977                         }
01978                         TempEffect = SHAPECLICK_PRIMARYCURVE;
01979                         goto FoundBlob;
01980                     }
01981                 }  
01982 
01983                 if (IsStellated())
01984                 {
01985                     // Test for the blob before the stellation point
01986                     if (IsStellationCurvature())
01987                     {
01988                         GetApplication()->GetBlobManager()->GetBlobRect(Array[Counter++],&BlobBounds);
01989                         if (BlobBounds.ContainsCoord(*pPos))
01990                         {
01991                             *pPos = Array[Counter-1];
01992                             *pPointNum = Counter-1;
01993                             if (pStart != NULL)
01994                                 *pStart = StellEnd;
01995                             if (pEnd != NULL)
01996                                 *pEnd = Start;
01997                             TempEffect = SHAPECLICK_STELLATIONCURVE;
01998                             goto FoundBlob;
01999                         }
02000                     }
02001                     
02002                     // Test the stellation point itself
02003                     GetApplication()->GetBlobManager()->GetBlobRect(Array[Counter++],&BlobBounds);
02004                     if (BlobBounds.ContainsCoord(*pPos))
02005                     {
02006                         *pPos = Array[Counter-1];
02007                         *pPointNum = Counter-1;
02008                         TempEffect = SHAPECLICK_STELLATION;
02009                         goto FoundBlob;
02010                     }
02011 
02012                     // Test for the blob after the stellation point
02013                     if (IsStellationCurvature())
02014                     {
02015                         GetApplication()->GetBlobManager()->GetBlobRect(Array[Counter++],&BlobBounds);
02016                         if (BlobBounds.ContainsCoord(*pPos))    
02017                         {
02018                             *pPos = Array[Counter-1];
02019                             *pPointNum = Counter-1;
02020                             if (pStart != NULL)
02021                                 *pStart = StellEnd;
02022                             if (pEnd != NULL)
02023                                 *pEnd = PrimeEnd;
02024                             TempEffect = SHAPECLICK_STELLATIONCURVE;
02025                             goto FoundBlob;
02026                         }
02027                     } 
02028                 }
02029 
02030                 if (IsPrimaryCurvature())
02031                 {
02032                     GetApplication()->GetBlobManager()->GetBlobRect(Array[Counter++],&BlobBounds);
02033                     if (BlobBounds.ContainsCoord(*pPos))
02034                     {
02035                         *pPos = Array[Counter-1];
02036                         *pPointNum = Counter-1;
02037                         if (pEnd != NULL)
02038                         {
02039                             if (IsStellated())
02040                                 *pEnd = StellEnd;
02041                             else
02042                                 *pEnd = Start;
02043                         }
02044                         if (pStart != NULL)
02045                             *pStart = PrimeEnd;
02046                         TempEffect = SHAPECLICK_PRIMARYCURVE;
02047                         goto FoundBlob;                     
02048                     }
02049                 }  
02050             }
02051         }
02052         FoundBlob:
02053         if (Array != NULL)
02054             delete [] Array;
02055         if ((TempEffect == SHAPECLICK_PRIMARY) && IsARectangle())
02056             TempEffect = SHAPECLICK_RECTANGLE;
02057         if (TempEffect != SHAPECLICK_NONE)
02058             return TempEffect;
02059     }
02060     else
02061     {
02062         // Ellipses have four blobs on major, minor, and the two opposite points
02063         // Is the pointer is over the major axes or its opposite?
02064         DocCoord Opposite = GetCentrePoint() - (GetMajorAxes() - GetCentrePoint());
02065         DocRect OppBounds;
02066         GetApplication()->GetBlobManager()->GetBlobRect(Opposite,&OppBounds);
02067         DocCoord Point = GetMajorAxes();
02068         GetApplication()->GetBlobManager()->GetBlobRect(Point,&BlobBounds);
02069         if (BlobBounds.ContainsCoord(*pPos))
02070         {
02071             *pPos = Point;
02072             return SHAPECLICK_ELLIPSE;
02073         }
02074         if (OppBounds.ContainsCoord(*pPos))
02075         {
02076             *pPos = Opposite;
02077             return SHAPECLICK_ELLIPSE;
02078         }
02079 
02080         // Or the minor axis point and its opposite?
02081         Opposite = GetCentrePoint() - (GetMinorAxes() - GetCentrePoint());
02082         GetApplication()->GetBlobManager()->GetBlobRect(Opposite,&OppBounds);
02083         Point = GetMinorAxes();
02084         GetApplication()->GetBlobManager()->GetBlobRect(Point,&BlobBounds);
02085         if (BlobBounds.ContainsCoord(*pPos))
02086         {
02087             *pPos = Point;
02088             return SHAPECLICK_ELLIPSE;
02089         }
02090         if (OppBounds.ContainsCoord(*pPos))
02091         {
02092             *pPos = Opposite;
02093             return SHAPECLICK_ELLIPSE;
02094         }
02095     }
02096 
02097     // Is the pointer is over the centre point?
02098     Interest = GetCentrePoint();
02099     GetApplication()->GetBlobManager()->GetBlobRect(Interest,&BlobBounds);
02100     if (BlobBounds.ContainsCoord(*pPos))
02101     {
02102         *pPos = Interest;       
02103         return SHAPECLICK_CENTRE;
02104     }
02105 
02106     // Is the pointer near enough to do edge distortion?
02107     // Ellipses cannot have their edges distorted
02108     if (!IsCircular())
02109     {
02110         Path* RenderPath = NULL;
02111         INT32 tempPos;
02112         BuildShapePath(&RenderPath);
02113         if (RenderPath->PointCloseToLine(*pPos, &tempPos))
02114         {
02115             // Now work out wether we are going to distort edge path one or two
02116             const UINT32 EdgePath1Count = EdgePath1.GetNumCoords()-1;
02117             const UINT32 EdgePath2Count = EdgePath2.GetNumCoords()-1;
02118             INT32 Current = EdgePath1Count;
02119             if (Current >= tempPos)
02120                 return SHAPECLICK_EDGE1;
02121             while (Current <= RenderPath->GetNumCoords()-1)
02122             {
02123                 if (Current >= tempPos)
02124                     return SHAPECLICK_EDGE1;
02125 
02126                 // Allow for stellation curvature
02127                 if (IsStellated() && IsStellationCurvature())
02128                 {
02129                     Current += 3;
02130                     if (Current >= tempPos)
02131                         return SHAPECLICK_NONE;
02132                 }
02133 
02134                 // We could now be sitting on the stellation path
02135                 if (IsStellated())
02136                 {
02137                     Current += EdgePath2Count;
02138                     if (Current >= tempPos)
02139                         return SHAPECLICK_EDGE2;
02140                 }
02141 
02142                 // Now account for primary curvature
02143                 if (IsPrimaryCurvature())
02144                 {
02145                     Current += 3;
02146                     if (Current >= tempPos)
02147                         return SHAPECLICK_NONE;
02148                 }
02149 
02150                 // Point to end of next primary path
02151                 Current += EdgePath1Count;
02152             }
02153             ERROR3("Didn't find Current in RenderPath!");
02154             return SHAPECLICK_NONE;
02155         }
02156     }
02157 
02158 #endif
02159 
02160     // To get here the pointer didn't excite anything, so return empty
02161     return SHAPECLICK_NONE;
02162 }
02163 
02164 
02165 
02166 
02167 /*******************************************************************************************
02168 
02169 >   BOOL NodeRegularShape::InsertShapeEdge(Path* RenderPath, Path* Edge, DocCoord NewEnd)
02170 
02171 
02172     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
02173     Created:    15/12/94
02174     Inputs:     RenderPath points to the path to insert the edge onto the end of
02175                 Edge points to the edge path
02176                 NewEnd is the point the new edge should end on.
02177     Outputs:    Appends a new edge onto the path pointed to by RenderPath
02178     Returns:    TRUE or FALSE depending on sucess 
02179     Purpose:    Adds another edge onto the current shape.  The edge runs from the current end
02180                 of RenderPath to the point defined by NewEnd
02181                 NOTE: Currently this routine assumes that the edge path consists of one Bezier
02182                 curve.  There is an ERROR3 to check this!
02183     SeeAlso:    NodeRegularShape::BuildShapePath
02184 
02185 ********************************************************************************************/
02186 BOOL NodeRegularShape::InsertShapeEdge(Path* RenderPath, Path* Edge, DocCoord NewEnd)
02187 {
02188     // We can cope with a single line or a single curve
02189     if (Edge->GetNumCoords() == 2)
02190     {
02191         return RenderPath->AddLineTo(NewEnd);
02192     }
02193     else
02194     {
02195         ERROR3IF(Edge->GetNumCoords() != 4,"The edge path did not consist of a single Bezier curve");
02196 
02197         DocCoord* EdgeCoords = Edge->GetCoordArray();
02198         DocCoord* RenderCoords = RenderPath->GetCoordArray();
02199 
02200         // Get the start and ends of the paths to normalise.
02201         DocCoord InsertStart = RenderCoords[RenderPath->GetNumCoords()-1];
02202         DocCoord EdgeStart = EdgeCoords[0];
02203         DocCoord EdgeEnd = EdgeCoords[3];
02204 
02205         // To avoid mathematical problems detect if the start point == then end point
02206         if (InsertStart == NewEnd)
02207         {
02208             return RenderPath->AddCurveTo(InsertStart, NewEnd, NewEnd);
02209         }
02210 
02211         // We have to position the two control points along the line from InsertStart to InsertEnd
02212         DocCoord ControlPoints[2];
02213         ControlPoints[0] = EdgeCoords[1] - EdgeCoords[0];
02214         ControlPoints[1] = EdgeCoords[2] - EdgeCoords[0];
02215         double ScaleFactor = InsertStart.Distance(NewEnd)/EdgeStart.Distance(EdgeEnd);
02216 
02217         double EdgeRotation = atan2( (double)(EdgeEnd.y-EdgeStart.y) , (double)(EdgeEnd.x-EdgeStart.x) );
02218         double InsertRotation = atan2( (double)(NewEnd.y-InsertStart.y) , (double)(NewEnd.x-InsertStart.x) );
02219         double theta = InsertRotation - EdgeRotation;
02220 
02221         double a = ScaleFactor * cos(theta);
02222         double b = ScaleFactor * sin(theta);
02223         double c = -ScaleFactor * sin(theta);
02224         double d = ScaleFactor * cos(theta);
02225         INT32 e = InsertStart.x;
02226         INT32 f = InsertStart.y;                                       
02227 
02228         Trans2DMatrix   Trans(Matrix(a,b,c,d,e,f));
02229         Trans.Transform( ControlPoints, 2);
02230 
02231         return RenderPath->AddCurveTo(ControlPoints[0], ControlPoints[1], NewEnd);
02232     }
02233 }
02234 
02235 
02236 
02237 /*******************************************************************************************
02238 
02239 >   BOOL NodeRegularShape::BuildEllipsePath(Path* RenderPath)
02240 
02241     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
02242     Created:    3/1/95
02243     Inputs:     RenderPath points to an uninitialised path object
02244     Outputs:    RenderPath will contain the ellipse path
02245     Returns:    TRUE or FALSE depending on whether the path was succesfully created
02246     Purpose:    This function is called to build a ellipitical render path.  It can build
02247                 the path directly around the CentrePoint.
02248     Errors:     Validity checks on the shape (is it circular?)
02249     SeeAlso:    NodeRegularShape::BuildShapePath
02250 
02251 ********************************************************************************************/
02252 BOOL NodeRegularShape::BuildEllipsePath(Path* RenderPath)
02253 {
02254     ERROR3IF(!IsCircular(),"BuildEllipsePath called for a non-elliptical shape");
02255 
02256     // Initialise the path
02257     if (!RenderPath->Initialise(12,4) )
02258     {
02259         return FALSE;
02260     }
02261 
02262     RenderPath->SetPathPosition(0);        
02263 
02264     // Get the major and minor axes, and the points opposite them.
02265     const DocCoord w( UTMinorAxes);
02266     const DocCoord x( UTCentrePoint + (UTCentrePoint - UTMajorAxes) );
02267     const DocCoord y( UTCentrePoint + (UTCentrePoint - UTMinorAxes) );
02268     const DocCoord z( UTMajorAxes );
02269 
02270     // Now get the points at the vertices of the parallogram.
02271     const DocCoord a( UTMinorAxes + (UTMajorAxes - UTCentrePoint) );
02272     const DocCoord b( UTMinorAxes - (UTMajorAxes - UTCentrePoint) );
02273     const DocCoord c( y - (UTMajorAxes - UTCentrePoint) );
02274     const DocCoord d( y + (UTMajorAxes - UTCentrePoint) );
02275 
02276     // Insert the path data
02277     BOOL Success = TRUE;
02278 //  const INT32 MidX = UTCentrePoint.x;
02279 //  const INT32 MidY = UTCentrePoint.y;
02280     DocCoord CP1;
02281     DocCoord CP2;
02282 
02283     // Add the moveto at the start of the path
02284     Success = RenderPath->AddMoveTo(z);
02285 
02286     // Add the first curve
02287     if (Success)
02288     {
02289         CP1 = DocCoord::PositionPointFromRatio(z, a, CurveFactor);
02290         CP2 = DocCoord::PositionPointFromRatio(w, a, CurveFactor);
02291         Success = RenderPath->AddCurveTo(CP1, CP2, w);
02292     }
02293 
02294     // and the second
02295     if (Success)
02296     {
02297         CP1 = DocCoord::PositionPointFromRatio(w, b, CurveFactor);
02298         CP2 = DocCoord::PositionPointFromRatio(x, b, CurveFactor);
02299         Success = RenderPath->AddCurveTo(CP1, CP2, x);
02300     }
02301 
02302     // and the third
02303     if (Success)
02304     {
02305         CP1 = DocCoord::PositionPointFromRatio(x, c, CurveFactor);
02306         CP2 = DocCoord::PositionPointFromRatio(y, c, CurveFactor);
02307         Success = RenderPath->AddCurveTo(CP1, CP2, y);
02308     }
02309 
02310     // and finally the fourth
02311     if (Success)
02312     {
02313         CP1 = DocCoord::PositionPointFromRatio(y, d, CurveFactor);
02314         CP2 = DocCoord::PositionPointFromRatio(z, d, CurveFactor);
02315         Success = RenderPath->AddCurveTo(CP1, CP2, z);
02316     }
02317 
02318     // Finish off the path by setting the close flags and filling it
02319     if (Success)
02320     {
02321         RenderPath->CloseSubPath();
02322         RenderPath->IsFilled = TRUE;
02323     }
02324 
02325     return Success;
02326 }
02327 
02328 
02329 
02330 class FloatCoord
02331 {
02332 public:
02333     FloatCoord() {};
02334     FloatCoord(double initX, double initY) {X = initX; Y = initY;};
02335     double X;
02336     double Y;
02337 };
02338 
02339 
02340 
02341 /*******************************************************************************************
02342 
02343 >   BOOL NodeRegularShape::BuildPolygonPoints(DocCoord** pArray, INT32* NumPoints = NULL)
02344 
02345     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
02346     Created:    3/1/95
02347     Inputs:     pArray points to a pointer to a DocCoord
02348                 NumPoints points to an INT32
02349     Outputs:    pArray will point to an array of DocCoords.  The array contains the
02350                 significant points of the shape 
02351                 NumPoints will contain the number of points in pArray
02352     Returns:    TRUE or FALSE for success/failure
02353     Purpose:    Use this function to build a array of significant locations on a polygonal shape
02354                 These are the primary and stellation points, also the primary and stellation
02355                 curvature points.  The significant points are only present in the array if the
02356                 shape has that feature enabled
02357                 NOTE: The first two points in the array are duplicated at the end of the array
02358                 to make BuildPolygonPath's life easier
02359     SeeAlso:    NodeRegularShape::BuildShapePath, NodeRegularShape::BuildPolygonPath
02360     Errors:     ERROR2 Validity checks on shape 
02361 
02362 ********************************************************************************************/
02363 BOOL NodeRegularShape::BuildPolygonPoints(DocCoord** pArray, INT32* NumPoints)
02364 {
02365     ERROR3IF(IsCircular(),"Can't build a points array for a circular shape!");
02366     ERROR2IF(NumSides == 0, FALSE, "Zero number of sides!");
02367     ERROR3IF(IsPrimaryCurvature() && !IsStellationCurvature(), "Shape has primary curvature but not stellation curvature");
02368     ERROR3IF(!IsPrimaryCurvature() && IsStellationCurvature(), "Shape has stellation curvature but not primary curvature");
02369 
02370     FloatCoord* pFloatArray = NULL;
02371     DocCoord* pDocArray = *pArray;
02372 
02373     // Claim the space for the two arrays.
02374     UINT32 FloatElements = NumSides;
02375     UINT32 DocElements = NumSides;
02376     if (IsStellated())
02377     {
02378         FloatElements += NumSides;
02379         DocElements += NumSides;
02380     }
02381     if (IsPrimaryCurvature())
02382         DocElements += NumSides*2;
02383     if (IsStellated() && IsStellationCurvature())
02384         DocElements += NumSides*2;
02385     DocElements += 3;
02386     FloatElements += 2;
02387 
02388     pFloatArray = new FloatCoord[FloatElements];
02389     pDocArray = new DocCoord[DocElements];
02390     *pArray = pDocArray;
02391 
02392     // Deal with lack of memory
02393     if ( (pDocArray == NULL) || (pFloatArray == NULL) )
02394     {
02395         if (pDocArray != NULL)
02396             delete [] pDocArray;
02397         if (pFloatArray != NULL)
02398             delete [] pFloatArray;
02399         return FALSE;
02400     }
02401     
02402     // Fill in the FloatArray with normalised coordinates
02403     double CurrentAngle = (float)(PI/NumSides);
02404     const double AngleInc = (float)((2*PI)/NumSides);
02405     const double StellationInc = (float)((AngleInc/2) + (StellOffsetRatio*AngleInc));
02406     const double MaxRadius = 0.5;
02407     double Radius = MaxRadius;
02408     double StellationRadius = Stellated ? (Radius * StellRadiusToPrimary) : Radius;
02409     if (StellationRadius > MaxRadius)
02410     {
02411         const double ratio = StellationRadius/Radius;
02412         Radius = Radius / ratio;
02413         StellationRadius = StellationRadius / ratio;
02414     }
02415     const FloatCoord InitialPrimaryPoint(0.0, Radius);
02416     const FloatCoord InitialStellationPoint(0.0, StellationRadius);
02417     UINT32 FloatCounter = 0;
02418     FloatCoord TempCoord;
02419 
02420     UINT32              CurrentSide;
02421     for( CurrentSide = 0; CurrentSide < NumSides; CurrentSide++)
02422     {
02423         // Calculate the position of the normalised points by rotation
02424         TempCoord.X = (float)(InitialPrimaryPoint.X*cos(CurrentAngle)
02425                                                 - InitialPrimaryPoint.Y*sin(CurrentAngle) + MaxRadius);
02426         TempCoord.Y = (float)(InitialPrimaryPoint.X*sin(CurrentAngle)
02427                                                 + InitialPrimaryPoint.Y*cos(CurrentAngle) + MaxRadius);
02428         pFloatArray[FloatCounter++] = TempCoord;
02429 
02430         // Now do the stellation point if the shape is stellated
02431         if (Stellated)
02432         {
02433             TempCoord.X = (float)(InitialStellationPoint.X*cos(CurrentAngle+StellationInc) 
02434                                 - InitialStellationPoint.Y*sin(CurrentAngle+StellationInc) + MaxRadius);
02435             TempCoord.Y = (float)(InitialStellationPoint.X*sin(CurrentAngle+StellationInc)
02436                                 + InitialStellationPoint.Y*cos(CurrentAngle+StellationInc) + MaxRadius);
02437             pFloatArray[FloatCounter++] = TempCoord;
02438         }
02439 
02440         CurrentAngle += AngleInc;
02441     }
02442     
02443     pFloatArray[FloatCounter] = pFloatArray[0];
02444     ERROR3IF(FloatCounter >= FloatElements, "Ran over end of FloatCoord array");
02445 
02446 /*UINT32 Temp = 0;
02447 PATRACE( _T("\n\nFloat Array"));
02448 for (CurrentSide = 0; CurrentSide < NumSides; CurrentSide++)
02449 {
02450     PATRACE( _T("Primary: %f,%f\n"), pFloatArray[Temp].X, pFloatArray[Temp++].Y);
02451     if (IsStellated())
02452         PATRACE( _T("Stellation: %f,%f\n"), pFloatArray[Temp].X, pFloatArray[Temp++].Y);
02453 }*/
02454 
02455     // Now copy the normalised coordinates into the DocCoord array, transforming them at the same time
02456     // Also insert the curvature points as required...
02457     DocCoord OuterMajor =  UTMajorAxes;
02458     DocCoord OuterMinor = UTMinorAxes;
02459     
02460     // if the stellations points are further from the centre than the primary points
02461     // then adjust the positioning length
02462     if (IsStellated() && (GetStellRadiusToPrimary() > 1.0))
02463     {
02464         PositionPointFromRatio(&OuterMajor, &UTMajorAxes, GetStellRadiusToPrimary());
02465         PositionPointFromRatio(&OuterMinor, &UTMinorAxes, GetStellRadiusToPrimary());
02466     }
02467 
02468     // Get the origin and two adjacent coordinates of the parallogram that we are trying to fit the
02469     // normalised coordinates into.
02470     const DocCoord ParallelOrigin(UTCentrePoint.x*3 - (OuterMajor.x + OuterMinor.x), 
02471                                             UTCentrePoint.y*3 - (OuterMajor.y + OuterMinor.y));
02472     const DocCoord ParallelA((OuterMajor.x - (OuterMinor.x-UTCentrePoint.x)) - ParallelOrigin.x,
02473                                 (OuterMajor.y - (OuterMinor.y-UTCentrePoint.y)) - ParallelOrigin.y);
02474     const DocCoord ParallelB((OuterMinor.x - (OuterMajor.x-UTCentrePoint.x)) - ParallelOrigin.x,
02475                                 (OuterMinor.y - (OuterMajor.y-UTCentrePoint.y)) - ParallelOrigin.y);
02476 
02477     UINT32 DocCounter = 0;
02478     FloatCounter = 0;
02479     DocCoord PrimaryPoint;
02480     DocCoord StellationPoint(0,0);
02481     DocCoord NextPrimary;
02482     
02483     // initialise NextPrimary for the first loop iteration
02484     FloatCoord InitPrimeFloat = pFloatArray[FloatCounter++];
02485     NextPrimary.x = (INT32)(InitPrimeFloat.X*ParallelB.x + InitPrimeFloat.Y*ParallelA.x) + ParallelOrigin.x;
02486     NextPrimary.y = (INT32)(InitPrimeFloat.X*ParallelB.y + InitPrimeFloat.Y*ParallelA.y) + ParallelOrigin.y;
02487 //  TransformMatrix.Transform(&NextPrimary,1);
02488 
02489     // process each FloatCoord into an actual DocCoord.  Leave room in the array to go back
02490     // and insert the curvature points, AFTER the primary&stellation points have been treansformed
02491     // to the actual document coordinates of the shape.
02492     for (CurrentSide = 0; CurrentSide < NumSides; CurrentSide++)
02493     {
02494         // Store the current primary point in the DocCoord array
02495         PrimaryPoint = NextPrimary;
02496         pDocArray[DocCounter++] = PrimaryPoint;
02497 
02498         // Get the stellation point
02499         if (IsStellated())
02500         {
02501             const FloatCoord StellFloat = pFloatArray[FloatCounter++];
02502             StellationPoint.x = (INT32)(StellFloat.X*ParallelB.x + StellFloat.Y*ParallelA.x) + ParallelOrigin.x;
02503             StellationPoint.y = (INT32)(StellFloat.X*ParallelB.y + StellFloat.Y*ParallelA.y) + ParallelOrigin.y;
02504 //          TransformMatrix.Transform(&StellationPoint,1);
02505         }
02506 
02507         // Get the next primary point
02508         const FloatCoord PrimeFloat = pFloatArray[FloatCounter++];
02509         NextPrimary.x = (INT32)(PrimeFloat.X*ParallelB.x + PrimeFloat.Y*ParallelA.x) + ParallelOrigin.x;
02510         NextPrimary.y = (INT32)(PrimeFloat.X*ParallelB.y + PrimeFloat.Y*ParallelA.y) + ParallelOrigin.y;
02511 //      TransformMatrix.Transform(&NextPrimary,1);
02512 
02513         if (IsPrimaryCurvature())
02514             DocCounter++;
02515 
02516         if (IsStellated())
02517         {
02518             if (IsStellationCurvature())
02519                 DocCounter ++;
02520 
02521             pDocArray[DocCounter++] = StellationPoint;
02522 
02523             if (IsStellationCurvature())
02524                 DocCounter ++;
02525         }
02526 
02527         if (IsPrimaryCurvature())
02528             DocCounter++;
02529     }
02530     pDocArray[DocCounter] = pDocArray[0];
02531 
02532     // Go through the DocCoord array, filling in the gaps left for the curvature points
02533     if (IsPrimaryCurvature())  // && IsStellationCurvature()
02534     {
02535         // Get the length of the major axis for fitting curvature lengths along
02536         double temp = UTCentrePoint.Distance(OuterMajor) ;
02537         const double OuterMajorLength = (temp > 1.0) ? (temp) : (1.0);
02538         const double PrimaryCurvatureLength = OuterMajorLength * GetPrimaryCurveToPrimary();
02539         const double StellationCurvatureLength = OuterMajorLength * GetStellCurveToStell();
02540 
02541         DocCounter = 0;
02542         DocCoord TempCoord;
02543 
02544         for (CurrentSide = 0; CurrentSide < NumSides; CurrentSide++)
02545         {
02546             DocCoord PrimaryPoint = pDocArray[DocCounter];
02547             DocCoord StellationPoint = pDocArray[DocCounter+3];
02548             DocCoord NextPrimary = IsStellated() ? pDocArray[DocCounter+6] : pDocArray[DocCounter+3];
02549 
02550             // if the shape has primary curvature then insert the primary curvature point between
02551             // either the next primary point or the setllation point, depending on stellationness
02552             if (IsStellated())
02553             {
02554                 // Fit the primary curvature point between the primary point and the stellation point
02555                 double DistanceToNext = PrimaryPoint.Distance(StellationPoint);
02556                 double FitRatio;
02557                 if ((DistanceToNext < 1.0) || ((PrimaryCurvatureLength + StellationCurvatureLength) < 1.0))
02558                     TempCoord = PrimaryPoint;
02559                 else
02560                 {
02561                     FitRatio = PrimaryCurvatureLength / DistanceToNext;
02562                     if ((PrimaryCurvatureLength + StellationCurvatureLength) > DistanceToNext)
02563                     {   
02564                         double Scaler = DistanceToNext / (PrimaryCurvatureLength + StellationCurvatureLength);
02565                         FitRatio = (PrimaryCurvatureLength * Scaler) / DistanceToNext;
02566                     }
02567                     TempCoord = DocCoord::PositionPointFromRatio(PrimaryPoint, StellationPoint, FitRatio); 
02568                 }
02569             }
02570             else
02571             {
02572                 // Fit the primary curvature point between the primary point and the next
02573                 double DistanceToNext = PrimaryPoint.Distance(NextPrimary);
02574                 double FitRatio = 0.5;
02575                 if (DistanceToNext < 1.0)
02576                     TempCoord = PrimaryPoint;
02577                 else
02578                 {
02579                     if ((PrimaryCurvatureLength + PrimaryCurvatureLength) < DistanceToNext)
02580                         FitRatio = PrimaryCurvatureLength / DistanceToNext;
02581             
02582                     TempCoord = DocCoord::PositionPointFromRatio(PrimaryPoint, NextPrimary, FitRatio);  
02583                 }
02584             }
02585             pDocArray[DocCounter+1] = TempCoord;
02586 
02587             if (IsStellated())
02588             {
02589                 // Fit the stellation curvature point between the primary point and the stellation point
02590                 double DistanceToNext = PrimaryPoint.Distance(StellationPoint);
02591                 if ((DistanceToNext < 1.0) || ((PrimaryCurvatureLength + StellationCurvatureLength) < 1.0))
02592                     TempCoord = StellationPoint;
02593                 else
02594                 {
02595                     double FitRatio = StellationCurvatureLength / DistanceToNext;
02596                     if ((PrimaryCurvatureLength + StellationCurvatureLength) > DistanceToNext)
02597                     {
02598                         double Scaler = DistanceToNext / (PrimaryCurvatureLength + StellationCurvatureLength);
02599                         FitRatio = (StellationCurvatureLength * Scaler) / DistanceToNext;
02600                     }
02601                     TempCoord = DocCoord::PositionPointFromRatio(StellationPoint, PrimaryPoint, FitRatio); 
02602                 }
02603                 pDocArray[DocCounter+2] = TempCoord;
02604 
02605                 // Fit the stellation curvature point between the stellation point and the next primary point
02606                 DistanceToNext = StellationPoint.Distance(NextPrimary);
02607                 if ((DistanceToNext < 1.0) || ((PrimaryCurvatureLength + StellationCurvatureLength) < 1.0))
02608                     TempCoord = StellationPoint;
02609                 else
02610                 {
02611                     double FitRatio = StellationCurvatureLength / DistanceToNext;
02612                     if ((PrimaryCurvatureLength + StellationCurvatureLength) > DistanceToNext)
02613                     {
02614                         double Scaler = DistanceToNext / (PrimaryCurvatureLength + StellationCurvatureLength);
02615                         FitRatio = (StellationCurvatureLength * Scaler) / DistanceToNext;
02616                     }
02617                     TempCoord = DocCoord::PositionPointFromRatio(StellationPoint, NextPrimary, FitRatio); 
02618                 }
02619                 pDocArray[DocCounter+4] = TempCoord;
02620             }
02621 
02622             // Fit the second primary curvature point either between the two primary points or
02623             // the stellation point and the next primary point
02624             if (IsStellated())
02625             {
02626                 // Fit the primary curvature point between the stellation point and the next primary point
02627                 double DistanceToNext = StellationPoint.Distance(NextPrimary);
02628                 if ((DistanceToNext < 1.0) || ((PrimaryCurvatureLength + StellationCurvatureLength) < 1.0))
02629                     TempCoord = StellationPoint;
02630                 else
02631                 {
02632                     double FitRatio = PrimaryCurvatureLength / DistanceToNext;
02633                     if ((PrimaryCurvatureLength + StellationCurvatureLength) > DistanceToNext)
02634                     {
02635                         double Scaler = DistanceToNext / (PrimaryCurvatureLength + StellationCurvatureLength);
02636                         FitRatio = (PrimaryCurvatureLength * Scaler) / DistanceToNext;
02637                     }
02638                     TempCoord = DocCoord::PositionPointFromRatio(NextPrimary, StellationPoint, FitRatio); 
02639                 }
02640             
02641                 pDocArray[DocCounter+5] = TempCoord;
02642             }
02643             else
02644             {
02645                 // Fit the primary curvature point between the primary point and the next
02646                 double DistanceToNext = PrimaryPoint.Distance(NextPrimary);
02647                 if (DistanceToNext < 1.0)
02648                     TempCoord = PrimaryPoint;
02649                 else
02650                 {
02651                     double FitRatio = 0.5;
02652                     if ((PrimaryCurvatureLength + PrimaryCurvatureLength) < DistanceToNext)
02653                         FitRatio = PrimaryCurvatureLength / DistanceToNext;
02654 
02655                     TempCoord = DocCoord::PositionPointFromRatio(NextPrimary, PrimaryPoint, FitRatio);  
02656                 }
02657                 pDocArray[DocCounter+2] = TempCoord;
02658             }
02659 
02660             // Now increment DocCounter to point at the next primary point
02661             DocCounter+=3;
02662             if (IsStellated())
02663                 DocCounter+=3;
02664         }
02665     }
02666 
02667     pDocArray[DocCounter++] = pDocArray[0];
02668     pDocArray[DocCounter] = pDocArray[1];
02669 
02670 /*// Will dump the doccoord array
02671 Temp = 0;
02672 PATRACE( _T("\n\nDocCoord Array"));
02673 for (CurrentSide = 0; CurrentSide < NumSides; CurrentSide++)
02674 {
02675     PATRACE( _T("Primary: %d,%d\n"), pDocArray[Temp].x, pDocArray[Temp++].y);
02676     if (IsPrimaryCurvature())
02677         PATRACE( _T("Primary Curvature: %d,%d\n"), pDocArray[Temp].x, pDocArray[Temp++].y);
02678     if (IsStellationCurvature())
02679         PATRACE( _T("Stellation Curvature: %d,%d\n"), pDocArray[Temp].x, pDocArray[Temp++].y);
02680     if (IsStellated())
02681         PATRACE( _T("Stellation: %d,%d\n"), pDocArray[Temp].x, pDocArray[Temp++].y);
02682     if (IsStellationCurvature())
02683         PATRACE( _T("Stellation Curvature: %d,%d\n"), pDocArray[Temp].x, pDocArray[Temp++].y);
02684     if (IsPrimaryCurvature())
02685         PATRACE( _T("Primary Curvature: %d,%d\n"), pDocArray[Temp].x, pDocArray[Temp++].y);
02686 }*/
02687 
02688     delete [] pFloatArray;
02689 
02690     ERROR3IF(DocCounter >= DocElements, "Ran over end of DocCoord array");
02691 
02692     if (NumPoints != NULL)
02693         *NumPoints = DocCounter+1;
02694     return TRUE;
02695 }   
02696 
02697 
02698 
02699 /*******************************************************************************************
02700 
02701 >   BOOL NodeRegularShape::BuildPolygonPath(Path* RenderPath, DocCoord* pArray)
02702 
02703     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
02704     Created:    4/1/95
02705     Inputs:     RenderPath points to the path to build the path into 
02706                 pArray points to the significant points array.
02707     Outputs:    RenderPath will contain a path describing the polygon.
02708     Returns:    TRUE or FALSE if the path build succedes/fails 
02709     Purpose:    Use this function to build a polygonal path.  The path forms a closed and
02710                 filled shape
02711     Errors:     Validation checks on the shape
02712     SeeAlso:    NodeRegularShape::BuildShapePath, NodeRegularShape::BuildPolygonPoints
02713 
02714 ********************************************************************************************/
02715 BOOL NodeRegularShape::BuildPolygonPath(Path* RenderPath, DocCoord* pArray)
02716 {
02717     ERROR2IF(NumSides == 0, FALSE, "This shape has zero sides!");
02718     ERROR3IF(IsCircular(), "Building a polygon path for an ellipse!");
02719 
02720     // Calculate the number of elements the path will need
02721     INT32 Slots = NumSides*(EdgePath1.GetNumCoords()-1);
02722     if (IsStellated())
02723         Slots += NumSides*(EdgePath2.GetNumCoords()-1);
02724     if (IsPrimaryCurvature())
02725         Slots += NumSides*4;
02726     if (IsStellationCurvature())
02727         Slots += (NumSides-1)*4;
02728 
02729     if (!RenderPath->Initialise(Slots,4) )
02730     {
02731         return FALSE;
02732     }
02733     RenderPath->SetPathPosition(0);
02734 
02735     UINT32 Counter = 0;
02736     BOOL Success = TRUE;
02737 
02738     // Insert the MoveTo at the start of the path
02739     if (IsPrimaryCurvature())
02740         Success = RenderPath->AddMoveTo(pArray[1]);
02741     else
02742         Success = RenderPath->AddMoveTo(pArray[0]);
02743 
02744     UINT32              CurrentSide;
02745     for( CurrentSide = 0; (CurrentSide < NumSides) && Success; CurrentSide++)
02746     {
02747         // Skip over the initial Primry point and the curvature point
02748         Counter ++;
02749         if (IsPrimaryCurvature())
02750             Counter++;
02751 
02752         // Insert edge path one so that it ends on the current coordinate.
02753         Success = InsertShapeEdge(RenderPath, &EdgePath1, pArray[Counter]);
02754 
02755         if (IsStellated())
02756         {
02757             // Insert the curve around the stellation point
02758             if (IsStellationCurvature() && Success)
02759             {
02760                 DocCoord CP1;
02761                 DocCoord CP2;
02762                 CP1 = DocCoord::PositionPointFromRatio(pArray[Counter], pArray[Counter+1], CurveFactor);
02763                 CP2 = DocCoord::PositionPointFromRatio(pArray[Counter+2], pArray[Counter+1], CurveFactor);
02764                 Success = RenderPath->AddCurveTo(CP1, CP2, pArray[Counter+2]);
02765                 Counter += 2;
02766             }
02767 
02768             if (Success)
02769             {
02770                 Success = InsertShapeEdge(RenderPath, &EdgePath2, pArray[Counter+1]);
02771                 Counter ++;
02772             }
02773         }
02774 
02775         // Now insert the curve around the primary point if required
02776         if (IsPrimaryCurvature() && Success)
02777         {
02778             DocCoord CP1;
02779             DocCoord CP2;
02780             CP1 = DocCoord::PositionPointFromRatio(pArray[Counter], pArray[Counter+1], CurveFactor);
02781             CP2 = DocCoord::PositionPointFromRatio(pArray[Counter+2], pArray[Counter+1], CurveFactor);
02782             Success = RenderPath->AddCurveTo(CP1, CP2, pArray[Counter+2]);
02783             Counter ++;
02784         }
02785     }
02786 
02787     if (!Success)
02788     {
02789         return FALSE;
02790     }
02791 
02792     // Close the path properly
02793     RenderPath->CloseSubPath();
02794     RenderPath->IsFilled = TRUE;
02795 
02796     // Now we should run around the path and smooth the joins between curvatures and edges.
02797     if (IsPrimaryCurvature() || IsStellationCurvature())
02798     {
02799         const UINT32 SizePath1 = EdgePath1.GetNumCoords()-1;
02800         const UINT32 SizePath2 = EdgePath2.GetNumCoords()-1;
02801         DocCoord* PathCoords = RenderPath->GetCoordArray();
02802         INT32 Current = 0;
02803 
02804         for (CurrentSide = 0; CurrentSide < NumSides; CurrentSide++)
02805         {
02806             // Skip over edge path 1
02807             Current += SizePath1;
02808 
02809             if (IsStellated())
02810             {
02811                 // do the stellation curvature
02812                 if (IsStellationCurvature())
02813                 {
02814                     SmoothCurvatureJoin(RenderPath, PathCoords, Current, FALSE);
02815                     Current += 3;
02816                     SmoothCurvatureJoin(RenderPath, PathCoords, Current, TRUE);
02817                 }
02818                 Current += SizePath2;
02819             }
02820 
02821             // Do the primary curvature
02822             if (IsPrimaryCurvature())
02823             {
02824                 SmoothCurvatureJoin(RenderPath, PathCoords, Current, FALSE);
02825                 Current += 3;
02826                 SmoothCurvatureJoin(RenderPath, PathCoords, Current, TRUE);
02827             }
02828         }
02829     }
02830 
02831     return TRUE;
02832 }
02833 
02834 
02835 
02836 /*******************************************************************************************
02837 
02838 >   BOOL NodeRegularShape::SmoothCurvatureJoin(Path* RenderPath, DocCoord* Coords, INT32 Index, BOOL MoveLeft)
02839 
02840     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
02841     Created:    10/1/95
02842     Inputs:     RenderPath - points to the path to smooth the joins in
02843                 Coords - points to the path coordinate array
02844                 Index points to the endpoint to smooth
02845                 MoveLeft is TRUE if the left hand control point should move, FALSE if the
02846                 right hand one should move.
02847     Outputs:    The control point in the Coords array will have moved
02848     Returns:    FALSE if an error occured
02849     Purpose:    This function is used to smooth the joins between edges paths and the 
02850                 curvature segments
02851     Errors:     Can error if the opposite control point cannot be found.
02852     SeeAlso:    OpEditRegularShape::Do
02853 
02854 ********************************************************************************************/
02855 BOOL NodeRegularShape::SmoothCurvatureJoin(Path* RenderPath, DocCoord* Coords, INT32 Index, BOOL MoveLeft)
02856 {
02857     // Dont do any smoothing if the edge is straight
02858     if ((RenderPath->GetVerbArray()[Index] & ~PT_CLOSEFIGURE) == PT_LINETO)
02859         return TRUE;
02860 
02861     ERROR3IF(Index == 0, "Index was 0.  Must be one or greater");
02862     const INT32 Oppo = RenderPath->FindOppositeControlPoint(Index-1);
02863     if (Oppo == -1)
02864         return TRUE;
02865 
02866     DocCoord CPLeft = Coords[Index-1];
02867     DocCoord Centre = Coords[Index];
02868     DocCoord CPRight = Coords[Oppo];
02869     DocCoord MoveCP;
02870 
02871     double LeftDist = Centre.Distance(CPLeft);
02872     double RightDist = Centre.Distance(CPRight);
02873 
02874     if ((LeftDist == 0.0) || (RightDist == 0.0))
02875         return TRUE;
02876 
02877     if (MoveLeft)
02878     {
02879         MoveCP = DocCoord::PositionPointFromRatio(Centre, CPRight, LeftDist/RightDist);
02880         Coords[Index-1] = Centre - (MoveCP - Centre);
02881     }
02882     else
02883     {
02884         MoveCP = DocCoord::PositionPointFromRatio(Centre, CPLeft, RightDist/LeftDist);
02885         Coords[Oppo] = Centre - (MoveCP - Centre);
02886     }
02887     return TRUE;
02888 }
02889 
02890 
02891 
02892 /*******************************************************************************************
02893 
02894 >   BOOL NodeRegularShape::ToggleCurvature()
02895 
02896     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
02897     Created:    6/1/95
02898     Inputs:     -
02899     Outputs:    The shape will have has its Primary and Setllation Curvature state toggled
02900     Returns:    TRUE or FALSE if the path toggle succedes/fails 
02901     Purpose:    This function will toggle the curvature state of the shape in an undoable
02902                 way by firing off an OpEditRegularShape
02903     Errors:     -
02904     SeeAlso:    OpEditRegularShape::Do
02905 
02906 ********************************************************************************************/
02907 BOOL NodeRegularShape::ToggleCurvature()
02908 {
02909 #ifndef STANDALONE
02910 
02911     EditRegularShapeParam ChangeData(this);
02912     if (IsPrimaryCurvature() || IsStellationCurvature())
02913     {
02914         ChangeData.NewPrimaryCurvature = EditRegularShapeParam::CHANGE_SETFALSE;
02915         ChangeData.NewStellationCurvature = EditRegularShapeParam::CHANGE_SETFALSE;
02916     }
02917     else
02918     {
02919         ChangeData.NewPrimaryCurvature = EditRegularShapeParam::CHANGE_SETTRUE;
02920         ChangeData.NewStellationCurvature = EditRegularShapeParam::CHANGE_SETTRUE;
02921     }
02922     OpDescriptor* Apple = OpDescriptor::FindOpDescriptor(CC_RUNTIME_CLASS(OpEditRegularShape));
02923     if (Apple != NULL)
02924     {
02925         Apple->Invoke(&ChangeData);
02926         return TRUE;
02927     }
02928     else
02929         return FALSE;
02930 #else
02931     return FALSE;
02932 #endif
02933 }
02934 
02935 
02936 #ifndef STANDALONE
02937 
02938 /*******************************************************************************************
02939 
02940 >   BOOL NodeRegularShape::ClickEllipse(DocCoord PointerPos, ClickType Click,
02941                                     ClickModifiers ClickMods, Spread* pSpread, BOOL DragCentre))
02942 
02943     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
02944     Created:    08/04/95
02945     Inputs:     PointerPos - the location of the click
02946                 Click - the type of the click
02947                 ClickMods - the current click modifiers
02948                 pSpread - pointer to the spread containing the shape
02949     Outputs:    -
02950     Returns:    TRUE if the click is used / FALSE if it isn't
02951     Purpose:    This function will handle clicks on an ellipse
02952                 Single - unused
02953                 Double - Change ellipse so it is a circle
02954                 Drag - Rotate and resize ellipse
02955     Errors:     -
02956     SeeAlso:    -
02957 
02958 ********************************************************************************************/
02959 BOOL NodeRegularShape::ClickEllipse(DocCoord PointerPos, ClickType Click, ClickModifiers ClickMods,
02960                                                                      Spread* pSpread, BOOL DragCentre)
02961 {
02962     if (IsCircular())
02963     {
02964         switch (Click)
02965         {
02966             case CLICKTYPE_DOUBLE:
02967             {
02968                 // A double click on a point is used to make the shape regular
02969                 if (!MakeRegular(PointerPos))
02970                     InformError();
02971                 return TRUE;
02972                 break;
02973             }
02974             case CLICKTYPE_DRAG:
02975             {
02976                 // A drag on the major axes is used to resize and rotate the shape
02977                 OpDragRegularShape* pOp = new (OpDragRegularShape);
02978                 if (pOp != NULL)
02979                 {
02980                     pOp->DoStartDragEdit( this, PointerPos, pSpread, OpDragRegularShape::DRAG_ELLIPSE, DragCentre);
02981                 }
02982                 return TRUE;
02983                 break;
02984             }
02985             default:
02986                 return FALSE;
02987         }
02988     }
02989     else
02990         return FALSE;
02991 }
02992 
02993 
02994 
02995 /*******************************************************************************************
02996 
02997 >   BOOL NodeRegularShape::ClickCentre(DocCoord PointerPos, ClickType Click,
02998                                                     ClickModifiers ClickMods, Spread* pSpread)
02999 
03000     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
03001     Created:    6/1/95
03002     Inputs:     PointerPos - the location of the click
03003                 Click - the type of the click
03004                 ClickMods - the current click modifiers
03005                 pSpread - pointer to the spread containing the shape
03006     Outputs:    -
03007     Returns:    TRUE if the click is used / FALSE if it isn't
03008     Purpose:    This function will handle clicks on a shapes centre axes point
03009                 Single - unused
03010                 Double - Toggle polygon/ellipse
03011                 Drag - Translate shape
03012     Errors:     -
03013     SeeAlso:    -
03014 
03015 ********************************************************************************************/
03016 BOOL NodeRegularShape::ClickCentre(DocCoord PointerPos, ClickType Click, ClickModifiers ClickMods, Spread* pSpread)
03017 {
03018     switch (Click)
03019     {
03020         case CLICKTYPE_DOUBLE:
03021         {
03022             // A double click on the centre point is used to toggle the shapes Ellipse/Polygon state
03023             EditRegularShapeParam ChangeData(this);
03024             if (IsCircular())
03025                 ChangeData.NewCircular = EditRegularShapeParam::CHANGE_SETFALSE;
03026             else
03027                 ChangeData.NewCircular = EditRegularShapeParam::CHANGE_SETTRUE;
03028             OpDescriptor* Apple = OpDescriptor::FindOpDescriptor(CC_RUNTIME_CLASS(OpEditRegularShape));
03029             if (Apple != NULL)
03030                 Apple->Invoke(&ChangeData); 
03031             return TRUE;
03032             break;
03033         }
03034         case CLICKTYPE_DRAG:
03035         {
03036             // A drag on the centre point is used to move the shape around
03037             OpDragRegularShape* pOp = new (OpDragRegularShape);
03038             if (pOp != NULL)
03039             {
03040                 pOp->DoStartDragEdit( this, PointerPos, pSpread, OpDragRegularShape::DRAG_CENTRE, TRUE);
03041             }
03042             return TRUE;
03043             break;
03044         }
03045         default:
03046             return FALSE;
03047     }
03048     return FALSE; // shouldn't get here but suppresses a warning
03049 }
03050 
03051 
03052 
03053 /*******************************************************************************************
03054 
03055 >   BOOL NodeRegularShape::ClickPrimary(DocCoord PointerPos, ClickType Click,
03056                                     ClickModifiers ClickMods, Spread* pSpread, BOOL DragCentre)
03057 
03058     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
03059     Created:    6/1/95
03060     Inputs:     PointerPos - the location of the click
03061                 Click - the type of the click
03062                 ClickMods - the current click modifiers
03063                 pSpread - pointer to the spread containing the shape
03064     Outputs:    -
03065     Returns:    TRUE if the click is used / FALSE if it isn't
03066     Purpose:    This function will handle clicks on any primary point on a shape
03067                 Single - unused
03068                 Double - Toggle curvature
03069                 Drag - Rotate and resize shape
03070     Errors:     -
03071     SeeAlso:    -
03072 
03073 ********************************************************************************************/
03074 BOOL NodeRegularShape::ClickPrimary(DocCoord PointerPos, ClickType Click, ClickModifiers ClickMods, Spread* pSpread, BOOL DragCentre)
03075 {
03076     switch (Click)
03077     {
03078         case CLICKTYPE_DOUBLE:
03079         {
03080             // A double click on a stellation point is used to toggle the shapes curvature state
03081             BOOL Result = ToggleCurvature();
03082             ERROR2IF(!Result, FALSE, "Toggle curvature failed - OpEditRegularShape is ill");
03083             return TRUE;
03084             break;
03085         }
03086         case CLICKTYPE_DRAG:
03087         {
03088             OpDragRegularShape* pOp = new (OpDragRegularShape);
03089             if (pOp != NULL)
03090             {
03091                 pOp->DoStartDragEdit( this, PointerPos, pSpread, OpDragRegularShape::DRAG_PRIMARY, DragCentre);
03092             }
03093             return TRUE;
03094             break;
03095         }
03096         default:
03097             return FALSE;
03098     }
03099 }
03100 
03101 
03102 
03103 /*******************************************************************************************
03104 
03105 >   BOOL NodeRegularShape::ClickStellation(DocCoord PointerPos, ClickType Click,
03106                                                     ClickModifiers ClickMods, Spread* pSpread)
03107 
03108     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
03109     Created:    6/1/95
03110     Inputs:     PointerPos - the location of the click
03111                 Click - the type of the click
03112                 ClickMods - the current click modifiers
03113                 pSpread - pointer to the spread containing the shape
03114     Outputs:    -
03115     Returns:    TRUE if the click is used / FALSE if it isn't
03116     Purpose:    This function will handle clicks on any stellation point on a shape
03117                 Single - unused
03118                 Double - Toggle curvature
03119                 Drag - Change stellation offset and radius
03120     Errors:     -
03121     SeeAlso:    -
03122 
03123 ********************************************************************************************/
03124 BOOL NodeRegularShape::ClickStellation(DocCoord PointerPos, ClickType Click, ClickModifiers ClickMods, Spread* pSpread)
03125 {
03126     switch (Click)
03127     {
03128         case CLICKTYPE_DOUBLE:
03129         {
03130             // A double click on a stellation point is used to toggle the shapes curvature state
03131             BOOL Result = ToggleCurvature();
03132             ERROR2IF(!Result, FALSE, "Toggle curvature failed - OpEditRegularShape is ill");
03133             return TRUE;
03134             break;
03135         }
03136         case CLICKTYPE_DRAG:
03137         {
03138             OpDragRegularShape* pOp = new (OpDragRegularShape);
03139             if (pOp != NULL)
03140             {
03141                 pOp->DoStartDragEdit( this, PointerPos, pSpread, OpDragRegularShape::DRAG_STELLATION, TRUE);
03142             }
03143             return TRUE;
03144             break;
03145         }
03146         default:
03147             return FALSE;
03148     }
03149 }
03150 
03151 
03152 
03153 /*******************************************************************************************
03154 
03155 >   BOOL NodeRegularShape::ClickPCurve(DocCoord PointerPos, ClickType Click,
03156                     ClickModifiers ClickMods, Spread* pSpread, DocCoord Start, DocCoord End)
03157 
03158     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
03159     Created:    6/1/95
03160     Inputs:     PointerPos - the location of the click
03161                 Click - the type of the click
03162                 ClickMods - the current click modifiers
03163                 pSpread - pointer to the spread containing the shape
03164                 Start - the start of the edge line to drag along
03165                 End - the end of the edge line to drag along
03166     Outputs:    -
03167     Returns:    TRUE if the click is used / FALSE if it isn't
03168     Purpose:    This function will handle clicks on any primay curvature blob on a shape
03169                 Single - unused
03170                 Double - Toggle curvature
03171                 Drag - Change curvature ratio
03172     Errors:     -
03173     SeeAlso:    -
03174 
03175 ********************************************************************************************/
03176 BOOL NodeRegularShape::ClickPCurve(DocCoord PointerPos, ClickType Click, ClickModifiers ClickMods, Spread* pSpread, DocCoord Start, DocCoord End)
03177 {
03178     switch (Click)
03179     {
03180         case CLICKTYPE_DOUBLE:
03181         {
03182             BOOL Result = ToggleCurvature();
03183             ERROR2IF(!Result, FALSE, "Toggle curvature failed - OpEditRegularShape is ill");
03184             return TRUE;
03185             break;
03186         }
03187         case CLICKTYPE_DRAG:
03188         {
03189             // A drag is used to change the primary curvature ratio
03190             OpDragRegularShape* pOp = new (OpDragRegularShape);
03191             if (pOp != NULL)
03192             {
03193                 pOp->DoStartDragEditCurve( this, PointerPos, pSpread,
03194                                                         OpDragRegularShape::DRAG_PRIMARYCURVE, Start, End);
03195             }   
03196             return TRUE;
03197             break;
03198         }
03199         default:
03200             return FALSE;
03201     }
03202 }
03203 
03204 
03205 
03206 /*******************************************************************************************
03207 
03208 >   BOOL NodeRegularShape::ClickSCurve(DocCoord PointerPos, ClickType Click,
03209                     ClickModifiers ClickMods, Spread* pSpread, DocCoord Start, DocCoord End)
03210 
03211     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
03212     Created:    6/1/95
03213     Inputs:     PointerPos - the location of the click
03214                 Click - the type of the click
03215                 ClickMods - the current click modifiers
03216                 pSpread - pointer to the spread containing the shape
03217                 Start - the start of the edge line to drag along
03218                 End - the end of the edge line to drag along
03219     Outputs:    -
03220     Returns:    TRUE if the click is used / FALSE if it isn't
03221     Purpose:    This function will handle clicks on any stellation curvature blob on a shape
03222                 Single - unused
03223                 Double - Toggle curvature
03224                 Drag - Change curvature ratio
03225     Errors:     -
03226     SeeAlso:    -
03227 
03228 ********************************************************************************************/
03229 BOOL NodeRegularShape::ClickSCurve(DocCoord PointerPos, ClickType Click, ClickModifiers ClickMods, Spread* pSpread, DocCoord Start, DocCoord End)
03230 {
03231     switch (Click)
03232     {
03233         case CLICKTYPE_DOUBLE:
03234         {
03235             BOOL Result = ToggleCurvature();
03236             ERROR2IF(!Result, FALSE, "Toggle curvature failed - OpEditRegularShape is ill");
03237             return TRUE;
03238             break;
03239         }
03240         case CLICKTYPE_DRAG:
03241         {
03242             // A drag is used to change the stellation curvature ratio
03243             OpDragRegularShape* pOp = new (OpDragRegularShape);
03244             if (pOp != NULL)
03245             {
03246                 pOp->DoStartDragEditCurve( this, PointerPos, pSpread,
03247                                                     OpDragRegularShape::DRAG_STELLATIONCURVE, Start, End);
03248             }
03249             return TRUE;
03250             break;
03251         }
03252         default:
03253             return FALSE;
03254     }
03255 }
03256 
03257 
03258 
03259 /*******************************************************************************************
03260 
03261 >   BOOL NodeRegularShape::ClickEdge(DocCoord PointerPos, ClickType Click,
03262                                         ClickModifiers ClickMods, Spread* pSpread, BOOL EdgeOne)
03263 
03264     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
03265     Created:    6/1/95
03266     Inputs:     PointerPos - the location of the click
03267                 Click - the type of the click
03268                 ClickMods - the current click modifiers
03269                 pSpread - pointer to the spread containing the shape
03270                 EdgeOne - TRUE if EdgePath1 is being dragged, FALSE if EdgePath2 is being dragged.
03271     Outputs:    -
03272     Returns:    TRUE if the click is used / FALSE if it isn't
03273     Purpose:    This function will handle clicks on the edge of a shape.
03274                 SingleClick - unused
03275                 DoubleClick - If constrained then reset the path edit to a straight line
03276                               In unconstrained then toggle stellation state
03277                 Drag - Reform the edge path 
03278     Errors:     -
03279     SeeAlso:    -
03280 
03281 ********************************************************************************************/
03282 BOOL NodeRegularShape::ClickEdge(DocCoord PointerPos, ClickType Click, ClickModifiers ClickMods, Spread* pSpread, BOOL EdgeOne)
03283 {
03284     switch (Click)
03285     {
03286         case CLICKTYPE_DOUBLE:
03287         {
03288             if (ClickMods.Constrain)
03289             {
03290                 if (!MakeStraight(EdgeOne))
03291                     InformError();
03292             }
03293             else
03294             {
03295                 // A double click on an edge is used to toggle the shapes stellation state
03296                 EditRegularShapeParam ChangeData(this);
03297                 if (IsStellated())
03298                     ChangeData.NewStellated = EditRegularShapeParam::CHANGE_SETFALSE;
03299                 else
03300                     ChangeData.NewStellated = EditRegularShapeParam::CHANGE_SETTRUE;
03301                 OpDescriptor* Apple = OpDescriptor::FindOpDescriptor(CC_RUNTIME_CLASS(OpEditRegularShape));
03302                 if (Apple != NULL)
03303                     Apple->Invoke(&ChangeData);
03304             }
03305             return TRUE;
03306             break;
03307         }
03308         case CLICKTYPE_DRAG:
03309         {
03310             // A drag on edges is used to reform the edge path
03311             if (!IsCircular())
03312             {
03313                 double pdist;
03314                 INT32 tempel;
03315                 Path* RenderPath = NULL;
03316                 BuildShapePath(&RenderPath);
03317                 RenderPath->SqrDistanceToPoint(PointerPos, &tempel, &pdist);
03318 
03319                 OpReformShapeEdge* pOpReshape = new OpReformShapeEdge;
03320                 if (pOpReshape == NULL)
03321                     InformError( _R(IDS_OUT_OF_MEMORY), _R(IDS_OK) );
03322                 else
03323                 {
03324                     pOpReshape->DoStartDragEdit(this, EdgeOne, PointerPos, pSpread, tempel);
03325                 }
03326             }
03327             return TRUE;
03328             break;
03329         }
03330         default:
03331             return FALSE;
03332     }
03333 }
03334 
03335 #endif
03336 
03337 /*******************************************************************************************
03338 
03339 >   BOOL NodeRegularShape::IsReformed()
03340 
03341     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
03342     Created:    20/1/95
03343     Inputs:     -
03344     Outputs:    -
03345     Returns:    TRUE if either of the shapes edges have been reformed / FALSE if they havent
03346     Purpose:    This function is used to see if a shape has been reformed or not.
03347     Errors:     -
03348     SeeAlso:    -
03349 
03350 ********************************************************************************************/
03351 BOOL NodeRegularShape::IsReformed()
03352 {
03353     INT32 loop;
03354     DocCoord* Coords1 = EdgePath1.GetCoordArray();
03355     INT32 NumCoords1 = EdgePath1.GetNumCoords()-1;
03356     DocCoord* Coords2 = EdgePath2.GetCoordArray();
03357     INT32 NumCoords2 = EdgePath2.GetNumCoords()-1;
03358 
03359     // If it's a line then it can't have been reformed
03360     if ((NumCoords1 == 2) && (NumCoords2 ==2))
03361         return FALSE;
03362 
03363     for (loop = 1; loop < NumCoords1 ; loop++)
03364     {
03365         if (DocCoord::DistanceFromLine(Coords1[0], Coords1[NumCoords1], Coords1[loop]) > 1.0)
03366             return TRUE;
03367     }
03368 
03369     for (loop = 1; loop < NumCoords2 ; loop++)
03370     {
03371         if (DocCoord::DistanceFromLine(Coords2[0], Coords2[NumCoords2], Coords2[loop]) > 1.0)
03372             return TRUE;
03373     }
03374 
03375     return FALSE;
03376 }
03377 
03378 
03379 
03380 /*******************************************************************************************
03381 
03382 >   double NodeRegularShape::GetRotationAngle()
03383 
03384     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
03385     Created:    24/1/95
03386     Inputs:     -
03387     Outputs:    -
03388     Returns:    The angle of rotation of this shape
03389     Purpose:    Call this function to get the current angle of rotation of this shape.
03390                 This can be ascertained from the centre point and the major axes point.
03391     Errors:     -
03392     SeeAlso:    NodeRenderableBounded::GetRotationAngle
03393 
03394 ********************************************************************************************/
03395 
03396 double NodeRegularShape::GetRotationAngle()
03397 {
03398     DocCoord Offset = GetMajorAxes() - GetCentrePoint();
03399     double Angle = atan2((double)Offset.y, (double)Offset.x);
03400     if (Angle == HUGE_VAL)
03401         Angle = 0.0;
03402 
03403     return Angle;
03404 }
03405 
03406 
03407 
03408 /*******************************************************************************************
03409 
03410 >   UINT32 NodeRegularShape::GetNumSides() const
03411 
03412     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
03413     Created:    1/2/95
03414     Inputs:     -
03415     Outputs:    -
03416     Returns:    The number of sides the object has (circular objects return their 'hidden'
03417                 number of sides)
03418     Purpose:    Call this function to get the number of sides in the shape
03419     Errors:     -
03420     SeeAlso:    NodeRegularShape::SetNumSides
03421 
03422 ********************************************************************************************/
03423 UINT32 NodeRegularShape::GetNumSides() const
03424 {
03425     return NumSides;
03426 }
03427 
03428 
03429 
03430 /*******************************************************************************************
03431 
03432 >   void NodeRegularShape::SetNumSides(INT32 NewNumSides)
03433 
03434     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
03435     Created:    1/2/95
03436     Inputs:     NewNumSides - The new number of sides
03437     Outputs:    -
03438     Returns:    -
03439     Purpose:    Call this function to set the number of side in the current object 
03440     Errors:     -
03441     SeeAlso:    NodeRegularShape::GetNumSides
03442 
03443 ********************************************************************************************/
03444 void NodeRegularShape::SetNumSides(UINT32 NewNumSides)
03445 {
03446     if (NewNumSides >= REGULARSHAPE_MINSIDES)
03447     {   NumSides = NewNumSides; 
03448         InvalidateCache();
03449     }
03450     else
03451     {
03452         ERROR3_PF(("Attempted to set %d number of sides",NewNumSides));
03453     }
03454 }              
03455 
03456 
03457 
03458 /*******************************************************************************************
03459 
03460 >   BOOL NodeRegularShape::IsCircular() const
03461 
03462     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
03463     Created:    1/2/95
03464     Inputs:     -
03465     Outputs:    -
03466     Returns:    TRUE if the shape is a circle, FALSE if it is a polygon
03467     Purpose:    Call this function to test the circular state of the shape.
03468     Errors:     -
03469     SeeAlso:    NodeRegularShape::SetCircular
03470 
03471 ********************************************************************************************/
03472 BOOL NodeRegularShape::IsCircular() const
03473 {
03474     // Note the bitfield has values 0 or -1 so we change it to a real BOOL
03475     return (Circular != 0);
03476 }
03477 
03478 
03479 
03480 /*******************************************************************************************
03481 
03482 >   void NodeRegularShape::SetCircular(BOOL Value)
03483 
03484     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
03485     Created:    1/2/95
03486     Inputs:     TRUE to make this shape circular - FALSE to make it a polygon
03487     Outputs:    -
03488     Returns:    -
03489     Purpose:    Call this function to set the circular state of the shape
03490     Errors:     -
03491     SeeAlso:    NodeRegularShape::IsCircular
03492 
03493 ********************************************************************************************/
03494 void NodeRegularShape::SetCircular(BOOL Value)
03495 {
03496     Circular = Value;
03497     InvalidateCache();
03498 }
03499 
03500 
03501 
03502 /*******************************************************************************************
03503 
03504 >   BOOL NodeRegularShape::IsStellated() const
03505 
03506     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
03507     Created:    1/2/95
03508     Inputs:     -
03509     Outputs:    -
03510     Returns:    TRUE if this shape is stellated - FALSE if it isn't
03511     Purpose:    Call this function to test the stallatioin state of a shape
03512     Errors:     -
03513     SeeAlso:    NodeRegularShape::SetStellated
03514 
03515 ********************************************************************************************/
03516 BOOL NodeRegularShape::IsStellated() const
03517 {
03518     // Note the bitfield has values 0 or -1 so we change it to a real BOOL
03519     return (Stellated != 0);
03520 }
03521 
03522 
03523 
03524 /*******************************************************************************************
03525 
03526 >   void NodeRegularShape::SetStellated(BOOL Value)
03527 
03528     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
03529     Created:    1/2/95
03530     Inputs:     Value - TRUE to make the shape stellated, FALSE to make it non-stellated
03531     Outputs:    -
03532     Returns:    -
03533     Purpose:    Call this function to set the stellation state of the shape
03534     Errors:     -
03535     SeeAlso:    NodeRegularShape::IsStellated
03536 
03537 ********************************************************************************************/
03538 void NodeRegularShape::SetStellated(BOOL Value)
03539 {
03540     Stellated = Value;
03541     InvalidateCache();
03542 }              
03543 
03544 
03545 
03546 /*******************************************************************************************
03547 
03548 >   BOOL NodeRegularShape::IsPrimaryCurvature() const
03549 
03550     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
03551     Created:    1/2/95
03552     Inputs:     -
03553     Outputs:    -
03554     Returns:    TRUE if the shape has primary curvature, FALSE if it dosent
03555     Purpose:    Call this function to test the primary curvature state of a shape
03556     Errors:     -
03557     SeeAlso:    NodeRegularShape::SetPrimaryCurvature
03558 
03559 ********************************************************************************************/
03560 BOOL NodeRegularShape::IsPrimaryCurvature() const
03561 {
03562     // Note the bitfield has values 0 or -1 so we change it to a real BOOL
03563     return (PrimaryCurvature != 0);
03564 }
03565 
03566 
03567 
03568 /*******************************************************************************************
03569 
03570 >   void NodeRegularShape::SetPrimaryCurvature(BOOL Value)
03571 
03572     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
03573     Created:    1/2/95
03574     Inputs:     Valus - TRUE to give the shape primary curvature - FALSE to remove it
03575     Outputs:    -
03576     Returns:    -
03577     Purpose:    Call this function to set the primary curvature state of the shape
03578     Errors:     -
03579     SeeAlso:    NodeRegularShape::IsPrimaryCurvature
03580 
03581 ********************************************************************************************/
03582 void NodeRegularShape::SetPrimaryCurvature(BOOL Value)
03583 {
03584     PrimaryCurvature = Value;
03585     InvalidateCache();
03586 }
03587 
03588 
03589 
03590 /*******************************************************************************************
03591 
03592 >   BOOL NodeRegularShape::IsStellationCurvature() const
03593 
03594     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
03595     Created:    1/2/95
03596     Inputs:     -
03597     Outputs:    -
03598     Returns:    TRUE if the shape has stellation curvature - FALSE if it hasn't
03599     Purpose:    Call this function to test the state of the shapes stellation curvature
03600     Errors:     -
03601     SeeAlso:    NodeRegularShape::SetStellationCurvature
03602 
03603 ********************************************************************************************/
03604 BOOL NodeRegularShape::IsStellationCurvature() const
03605 {
03606     // Note the bitfield has values 0 or -1 so we change it to a real BOOL
03607     return (StellationCurvature != 0);
03608 }
03609 
03610 
03611 
03612 /*******************************************************************************************
03613 
03614 >   void NodeRegularShape::SetStellationCurvature(BOOL Value)
03615 
03616     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
03617     Created:    1/2/95
03618     Inputs:     Value - TRUE to give the shape stellation curvature - FALSE to clear it
03619     Outputs:    -
03620     Returns:    -
03621     Purpose:    Call this function to set the stellation curvature state of the shape
03622     Errors:     -
03623     SeeAlso:    NodeRegularShape::IsStellationCurvature
03624 
03625 ********************************************************************************************/
03626 void NodeRegularShape::SetStellationCurvature(BOOL Value)
03627 {
03628     StellationCurvature = Value;
03629     InvalidateCache();
03630 }
03631 
03632 
03633 
03634 /*******************************************************************************************
03635 
03636 >   double NodeRegularShape::GetStellRadiusToPrimary() const
03637 
03638     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
03639     Created:    1/2/95
03640     Inputs:     -
03641     Outputs:    -
03642     Returns:    The ratio of the stellation radius to the primary radius.
03643     Purpose:    Call this function to get the stellation radius ratio
03644     Errors:     -
03645     SeeAlso:    NodeRegularShape::SetStellRadiusToPrimary
03646 
03647 ********************************************************************************************/
03648 double NodeRegularShape::GetStellRadiusToPrimary() const
03649 {
03650     return StellRadiusToPrimary;
03651 }
03652 
03653 
03654 
03655 /*******************************************************************************************
03656 
03657 >   void NodeRegularShape::SetStellRadiusToPrimary(double Value)
03658 
03659     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
03660     Created:    1/2/95
03661     Inputs:     Value - the new stellation radius ratio
03662     Outputs:    -
03663     Returns:    -
03664     Purpose:    Call this function to set the stellation radius ratio
03665     Errors:     -
03666     SeeAlso:    NodeRegularShape::GetStellRadiusToPrimary
03667 
03668 ********************************************************************************************/
03669 void NodeRegularShape::SetStellRadiusToPrimary(double Value)
03670 {
03671     StellRadiusToPrimary = Value;
03672     InvalidateCache();
03673 }                  
03674 
03675 
03676 
03677 /*******************************************************************************************
03678 
03679 >   double NodeRegularShape::GetPrimaryCurveToPrimary() const
03680 
03681     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
03682     Created:    1/2/95
03683     Inputs:     -
03684     Outputs:    -
03685     Returns:    The primary curvature ratio (it's a ratio of the distance along the line
03686                 connecting a primary point to the next primary/stellation point
03687     Purpose:    Call this function to get the primary curvature ratio
03688     Errors:     -
03689     SeeAlso:    NodeRegularShape::SetPrimaryCurveToPrimary
03690 
03691 ********************************************************************************************/
03692 double NodeRegularShape::GetPrimaryCurveToPrimary() const
03693 {
03694     return PrimaryCurveToPrimary;
03695 }
03696 
03697 
03698 
03699 /*******************************************************************************************
03700 
03701 >   void NodeRegularShape::SetPrimaryCurveToPrimary(double Value)
03702 
03703     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
03704     Created:    1/2/95
03705     Inputs:     Value - the new value of the primary curvature ratio
03706     Outputs:    -
03707     Returns:    -
03708     Purpose:    Call this function to set the value of the primary curvature ratio 
03709     Errors:     -
03710     SeeAlso:    NodeRegularShape::GetPrimaryCurveToPrimary
03711 
03712 ********************************************************************************************/
03713 void NodeRegularShape::SetPrimaryCurveToPrimary(double Value)
03714 {
03715     PrimaryCurveToPrimary = Value;
03716     InvalidateCache();
03717 }
03718 
03719 
03720 
03721 /*******************************************************************************************
03722 
03723 >   double NodeRegularShape::GetStellCurveToStell() const
03724 
03725     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
03726     Created:    1/2/95
03727     Inputs:     -
03728     Outputs:    -
03729     Returns:    The stellation curvature ratio (it's a ratio of the distance along the line
03730                 connecting a stellation point to the next primary point)
03731     Purpose:    Call this function to get the stellation curvature ratio
03732     Errors:     -
03733     SeeAlso:    NodeRegularShape::SetStellCurveToStell
03734 
03735 ********************************************************************************************/
03736 double NodeRegularShape::GetStellCurveToStell() const
03737 {
03738     return StellCurveToStell;
03739 }
03740 
03741 
03742 
03743 /*******************************************************************************************
03744 
03745 >   void NodeRegularShape::GetRotationAngle(double Value)
03746 
03747     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
03748     Created:    1/2/95
03749     Inputs:     Value - the new stellation curvature ratio
03750     Outputs:    -
03751     Returns:    -
03752     Purpose:    Call this function to set the stellation curvature ratio
03753     Errors:     -
03754     SeeAlso:    NodeRegularShape::GetStellCurveToStell
03755 
03756 ********************************************************************************************/
03757 void NodeRegularShape::SetStellCurveToStell(double Value)
03758 {
03759     StellCurveToStell = Value;
03760     InvalidateCache();
03761 }                  
03762 
03763 
03764 
03765 /*******************************************************************************************
03766 
03767 >   double NodeRegularShape::GetStellationRatio() const
03768 
03769     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
03770     Created:    1/2/95
03771     Inputs:     -
03772     Outputs:    -
03773     Returns:    The stellation offset ratio.  This is a ratio of something to something else
03774     Purpose:    Call this function to get the stellation offset ratio
03775     Errors:     -
03776     SeeAlso:    NodeRegularShape::SetStellationRatio
03777 
03778 ********************************************************************************************/
03779 double NodeRegularShape::GetStellationRatio() const
03780 {
03781     return StellOffsetRatio;
03782 }
03783 
03784 
03785 
03786 /*******************************************************************************************
03787 
03788 >   void NodeRegularShape::SetStellationRatio(double Value)
03789 
03790     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
03791     Created:    1/2/95
03792     Inputs:     Value - the new value of the stellation offset
03793     Outputs:    -
03794     Returns:    -
03795     Purpose:    Call this function to set the stellation offset 
03796     Errors:     -
03797     SeeAlso:    NodeRegularShape::GetStellationRatio
03798 
03799 ********************************************************************************************/
03800 void NodeRegularShape::SetStellationRatio(double Value)
03801 {
03802     StellOffsetRatio = Value;
03803     InvalidateCache();
03804 }
03805 
03806 
03807 
03808 /*******************************************************************************************
03809 
03810 >   DocCoord NodeRegularShape::GetCentrePoint()
03811 
03812     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
03813     Created:    1/2/95
03814     Inputs:     -
03815     Outputs:    -
03816     Returns:    The location of the transfomed centre point
03817     Purpose:    Call this function to get the current centre point of the shape
03818     Errors:     -
03819     SeeAlso:    NodeRegularShape::SetCentrePoint
03820 
03821 ********************************************************************************************/
03822 DocCoord NodeRegularShape::GetCentrePoint()
03823 {
03824     DocCoord Result = UTCentrePoint;
03825     TransformMatrix.transform(&Result);
03826     return Result;
03827 }
03828 
03829 
03830 
03831 /*******************************************************************************************
03832 
03833 >   DocCoord NodeRegularShape::GetMajorAxes()
03834 
03835     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
03836     Created:    1/2/95
03837     Inputs:     -
03838     Outputs:    -
03839     Returns:    The transformed major point of the shape
03840     Purpose:    Call this function to get the shapes current major point
03841     Errors:     -
03842     SeeAlso:    NodeRegularShape::SetMajorAxes
03843 
03844 ********************************************************************************************/
03845 DocCoord NodeRegularShape::GetMajorAxes()
03846 {
03847     DocCoord Result = UTMajorAxes;
03848     TransformMatrix.transform(&Result);
03849     return Result;
03850 }
03851 
03852 
03853 /*******************************************************************************************
03854 
03855 >   DocCoord NodeRegularShape::GetMinorAxes()
03856 
03857     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
03858     Created:    1/2/95
03859     Inputs:     -
03860     Outputs:    -
03861     Returns:    The transformed minor point of the shape
03862     Purpose:    Call this function to get the current minor point of the shape
03863     Errors:     -
03864     SeeAlso:    NodeRegularShape::SetMinorAxes
03865 
03866 ********************************************************************************************/
03867 DocCoord NodeRegularShape::GetMinorAxes()
03868 {
03869     DocCoord Result = UTMinorAxes;
03870     TransformMatrix.transform(&Result);
03871     return Result;
03872 }
03873 
03874 
03875 
03876 /*******************************************************************************************
03877 
03878 >   void NodeRegularShape::SetCentrePoint(DocCoord Value)
03879 
03880     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
03881     Created:    1/2/95
03882     Inputs:     Value - the new centre point of the shape
03883     Outputs:    -
03884     Returns:    -
03885     Purpose:    Call this function to set the untransformed centre point of the shape
03886                 DO NOT use this function to move shapes around - apply transforms to it instead
03887     Errors:     -
03888     SeeAlso:    NodeRegularShape::GetCentrePoint
03889 
03890 ********************************************************************************************/
03891 void NodeRegularShape::SetCentrePoint(DocCoord Value)
03892 {
03893     UTCentrePoint = Value;
03894     InvalidateCache();
03895 }                  
03896 
03897 
03898 
03899 /*******************************************************************************************
03900 
03901 >   void NodeRegularShape::SetMinorAxes(DocCoord Value)
03902 
03903     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
03904     Created:    1/2/95
03905     Inputs:     Value - the new location of the minor point
03906     Outputs:    -
03907     Returns:    -
03908     Purpose:    Call this function to set the location of the minor axes point
03909                 DO NOT use this function to move shapes around - apply transforms to it instead
03910     Errors:     -
03911     SeeAlso:    NodeRegularShape::GetMinorAxes
03912 
03913 ********************************************************************************************/
03914 void NodeRegularShape::SetMinorAxes(DocCoord Value)
03915 {
03916     UTMinorAxes = Value;
03917     InvalidateCache();
03918 }                  
03919 
03920 
03921 
03922 /*******************************************************************************************
03923 
03924 >   void NodeRegularShape::SetMajorAxes(DocCoord Value)
03925 
03926     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
03927     Created:    1/2/95
03928     Inputs:     Value - the new location of the major point
03929     Outputs:    -
03930     Returns:    -
03931     Purpose:    Call this function to set the location of the major axes point 
03932                 DO NOT use this function to move shapes around - apply transforms to it instead
03933     Errors:     -
03934     SeeAlso:    NodeRegularShape::GetMajorAxes
03935 
03936 ********************************************************************************************/
03937 void NodeRegularShape::SetMajorAxes(DocCoord Value)
03938 {
03939     UTMajorAxes = Value;
03940     InvalidateCache();
03941 }       
03942 
03943 
03944 
03945 /*******************************************************************************************
03946 
03947 >   void NodeRegularShape::GetTransformMatrix(Matrix* store) const
03948 
03949     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
03950     Created:    2/2/95
03951     Inputs:     store - points to a Matrix object
03952     Outputs:    store will contain the shapes current transform matrix
03953     Returns:    -
03954     Purpose:    Call this function to get the shapes current transformation matrix
03955     Errors:     -
03956     SeeAlso:    -
03957 
03958 ********************************************************************************************/
03959 void NodeRegularShape::GetTransformMatrix(Matrix* store) const
03960 {
03961     *store = TransformMatrix;
03962 }
03963 
03964 
03965 
03966 /*******************************************************************************************
03967 
03968 >   void NodeRegularShape::SetTransformMatrix(const Matrix* newmatrix)
03969 
03970     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
03971     Created:    2/2/95
03972     Inputs:     newmatrix - points to a Trans2DMatrix object
03973     Outputs:    -
03974     Returns:    -
03975     Purpose:    Call this function to set the shapes current transformation matrix
03976     Errors:     -
03977     SeeAlso:    -
03978 
03979 ********************************************************************************************/
03980 void NodeRegularShape::SetTransformMatrix(const Matrix* newmatrix)
03981 {
03982     TransformMatrix = *newmatrix;
03983 }
03984 
03985 
03986 
03987 /*******************************************************************************************
03988 
03989 >   void NodeRegularShape::PreExportRender(RenderRegion* pRegion)
03990 
03991     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
03992     Created:    2/2/95
03993     Inputs:     pRegion - points to the export render region
03994     Outputs:    -
03995     Returns:    -
03996     Purpose:    This function is called just before the shape is exported.  It outputs the 
03997                 shapes start token
03998     Errors:     -
03999     SeeAlso:    NodeRegularShape::ExportRender
04000 
04001 ********************************************************************************************/
04002 void NodeRegularShape::PreExportRender(RenderRegion* pRegion)
04003 {
04004 #ifdef DO_EXPORT
04005     if (pRegion->IsKindOf(CC_RUNTIME_CLASS(NativeRenderRegion)))
04006     {
04007         // Output "start regular shape" token
04008         EPSExportDC *pDC = (EPSExportDC *) pRegion->GetRenderDC();
04009         pDC->OutputToken(_T("csrs"));
04010         pDC->OutputNewLine();
04011     }
04012 #endif
04013 }
04014 
04015 
04016 
04017 /*******************************************************************************************
04018 
04019 >   void NodeRegularShape::ExportRender(RenderRegion* pRegion)
04020 
04021     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
04022     Created:    2/2/95
04023     Inputs:     pRegion - points to the export render region
04024     Outputs:    -
04025     Returns:    -
04026     Purpose:    This function is called to export a regular shape as EPS
04027     Errors:     -
04028     SeeAlso:    NodeRegularShape::PreExportRender
04029 
04030 ********************************************************************************************/
04031 BOOL NodeRegularShape::ExportRender(RenderRegion* pRegion) 
04032 {
04033 #ifdef DO_EXPORT
04034     if (pRegion->IsKindOf(CC_RUNTIME_CLASS(NativeRenderRegion)))
04035     {
04036         EPSExportDC *pDC = (EPSExportDC *) pRegion->GetRenderDC();
04037 
04038         // Work out if the shape is filled or stroked.
04039         INT32 IsFilled = TRUE;
04040         StrokeColourAttribute *pStrokeColour =
04041             (StrokeColourAttribute *) pRegion->GetCurrentAttribute(ATTR_STROKECOLOUR);
04042         INT32 IsStroked = !pStrokeColour->Colour.IsTransparent();
04043 
04044         ColourFillAttribute *pFillAttr = 
04045             (ColourFillAttribute *) pRegion->GetCurrentAttribute(ATTR_FILLGEOMETRY);
04046     
04047         if (pFillAttr->IsKindOf(CC_RUNTIME_CLASS(FlatFillAttribute)) &&
04048             pFillAttr->Colour.IsTransparent())
04049         {
04050             // Flat fill with transparent colour => no fill
04051             IsFilled = FALSE;
04052         }
04053 
04054         // Output regular shape parameters
04055         pDC->OutputValue((INT32)NumSides);
04056         pDC->OutputValue((INT32)Circular);
04057         pDC->OutputValue((INT32)Stellated);
04058         pDC->OutputValue((INT32)PrimaryCurvature);
04059         pDC->OutputValue((INT32)StellationCurvature);
04060         pDC->OutputReal(StellRadiusToPrimary);
04061         pDC->OutputReal(PrimaryCurveToPrimary);
04062         pDC->OutputReal(StellCurveToStell);
04063         pDC->OutputReal(StellOffsetRatio);
04064         pDC->OutputCoord(UTCentrePoint);
04065         pDC->OutputCoord(UTMajorAxes);
04066         pDC->OutputCoord(UTMinorAxes);
04067         pDC->OutputValue(IsFilled);
04068         pDC->OutputValue(IsStroked);
04069         pDC->OutputToken(_T("crsp"));
04070         pDC->OutputNewLine();
04071 
04072         // Output the transformation matrix
04073         fixed16 billy[4];
04074         INT32 bobby[2];
04075         TransformMatrix.GetComponents(billy, bobby);
04076         pDC->OutputReal(billy[0].MakeDouble());
04077         pDC->OutputReal(billy[1].MakeDouble());
04078         pDC->OutputReal(billy[2].MakeDouble());
04079         pDC->OutputReal(billy[3].MakeDouble());
04080         pDC->OutputUserSpaceValue(bobby[0]);
04081         pDC->OutputUserSpaceValue(bobby[1]);
04082         pDC->OutputToken(_T("crstm"));
04083         pDC->OutputNewLine();
04084 
04085         // Output the paths for the shape's two edges
04086         ((EPSRenderRegion*)pRegion)->ExportPath(&EdgePath1, TRUE);
04087         pDC->OutputToken(_T("crsp1"));
04088         pDC->OutputNewLine();
04089         ((EPSRenderRegion*)pRegion)->ExportPath(&EdgePath2, TRUE);
04090         pDC->OutputToken(_T("crsp2"));
04091         pDC->OutputNewLine();
04092 
04093         // End the regular shape object
04094         pDC->OutputToken(_T("cers"));
04095         pDC->OutputNewLine();
04096                 
04097         // Tell caller we rendered ourselves ok
04098         return TRUE;
04099     }
04100 
04101     // This is necessary, because this ExportRender function hides the custom export code
04102     // used by the Flash render region in its base class.
04103     else if ( pRegion->IsKindOf ( CC_RUNTIME_CLASS ( FlashRenderRegion ) ) )
04104     {
04105         // Call the function to render a stroked shape.
04106         return static_cast<FlashRenderRegion*> ( pRegion )->ExportRenderableNode ( this );
04107     }
04108 
04109 #endif
04110     // Render the node in the normal way
04111     return FALSE;
04112 }
04113 
04114 /*******************************************************************************************
04115 
04116 >   void NodeRegularShape::EmergencyFixShape()
04117 
04118     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
04119     Created:    15/03/95
04120     Inputs:     -
04121     Outputs:    UTMajorPoint,UTMinorPoint and UTCentrePoint may be moved.  If they are then
04122                 the transform matrix is reset.
04123     Returns:    -
04124     Purpose:    This function checks to see if either the transformed major or minor axis
04125                 points are sitting on the transformed centre point.  If they are then the
04126                 shape is bodged to fix up the situation.
04127     Errors:     -
04128     SeeAlso:    -
04129 
04130 ********************************************************************************************/
04131 void NodeRegularShape::EmergencyFixShape()
04132 {
04133     DocCoord CurrentCentre = GetCentrePoint();
04134     DocCoord CurrentMajor = GetMajorAxes();
04135     DocCoord CurrentMinor = GetMinorAxes();
04136 
04137     if ( (CurrentCentre.Distance(CurrentMajor) == 0.0) ||
04138          (CurrentCentre.Distance(CurrentMinor) == 0.0) )
04139     {
04140         SetCentrePoint(CurrentCentre);
04141         SetMajorAxes(DocCoord(CurrentCentre.x+100, CurrentCentre.y));
04142         SetMinorAxes(DocCoord(CurrentCentre.x, CurrentCentre.y+100));
04143 
04144         Matrix fred( FIXED16(1), FIXED16(0), FIXED16(0), FIXED16(1), 0, 0 );
04145         SetTransformMatrix(&fred);
04146     }
04147 }
04148 
04149 
04150 
04151 /*******************************************************************************************
04152 
04153 >   BOOL NodeRegularShape::IsARectangle()
04154 
04155     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
04156     Created:    29/03/95
04157     Inputs:     -
04158     Outputs:    -
04159     Returns:    TRUE if this shape is a rectangle
04160                 FALSE if it isn't
04161     Purpose:    Offical, approved, way of seeing if a RegularShape is a rectangluar QuickShape
04162     Errors:     -
04163     SeeAlso:    -
04164 
04165 ********************************************************************************************/
04166 BOOL NodeRegularShape::IsARectangle() const
04167 {
04168     return (!IsCircular() && (GetNumSides() == 4) && !IsStellated());
04169 }
04170 
04171 
04172 /******************************************************************************************
04173 
04174 >   INT32 NodeRegularShape::GetRectWidth()
04175     
04176       Author:   Claude_Quemerais (Xara Group Ltd) <camelotdev@xara.com>
04177       Created:  08/08/96
04178       Inputs: -
04179       Outputs: The rectangle's width if it's a rectangle
04180                 -1 if it's not
04181       Purpose: Use this function to get the width  
04182 
04183 ******************************************************************************************/
04184 INT32 NodeRegularShape::GetRectWidth() 
04185 {
04186     if(!IsARectangle())
04187         return -1;
04188 
04189     double minorRadius = GetCentrePoint().Distance(GetMinorAxes());
04190     return (INT32)(minorRadius * cos(PI/4));
04191 }
04192 
04193 /******************************************************************************************
04194 
04195 >   INT32 NodeRegularShape::GetRectHeight()
04196     
04197       Author:   Claude_Quemerais (Xara Group Ltd) <camelotdev@xara.com>
04198       Created:  08/08/96
04199       Inputs: -
04200       Outputs: The rectangle's height if it's a rectangle
04201                 -1 if it's not
04202       Purpose: Use this function to get the height 
04203 
04204 ******************************************************************************************/
04205 INT32 NodeRegularShape::GetRectHeight()
04206 {
04207     if(!IsARectangle())
04208         return -1;
04209 
04210     double MajorRadius = GetCentrePoint().Distance(GetMajorAxes());
04211     return (INT32)(MajorRadius * cos(PI/4));
04212 }
04213 
04214 /********************************************************************************************
04215 
04216 >   virtual BOOL NodeRegularShape::OnNodePopUp(Spread* pSpread, DocCoord PointerPos, ContextMenu* pMenu)
04217 
04218     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
04219     Created:    16/04/95
04220     Inputs:     pSpread     The spread in which things are happening
04221                 PointerPos  The Location of the mouse pointer at the time of the click
04222                 pMenu       The menu to which items should be added
04223     Returns:    BOOL - TRUE if the node claims the click as its own and FALSE if it is
04224                 not interested in the click
04225     Purpose:    Allows the QuickShape to respond to pop up menu clicks on itself.
04226 
04227 ********************************************************************************************/
04228 
04229 BOOL NodeRegularShape::OnNodePopUp(Spread* pSpread, DocCoord PointerPos, ContextMenu* pMenu)
04230 {
04231 #if !defined(EXCLUDE_FROM_RALPH)
04232     BOOL ok = TRUE;
04233     
04234     ok = ok && pMenu->BuildCommand(TOOL_OPTOKEN_REGSHAPE, TRUE);
04235 
04236     ok = ok && pMenu->BuildCommand(OPTOKEN_TOGGLEELIPPOLY, TRUE);
04237     ok = ok && pMenu->BuildCommand(OPTOKEN_TOGGLESTELLATION);
04238     ok = ok && pMenu->BuildCommand(OPTOKEN_TOGGLECURVATURE, TRUE);
04239 
04240     ok = ok && pMenu->BuildCommand(OPTOKEN_QUICKSHAPE_NUMBERSIDES,TRUE);
04241     MenuItem* pNumberRoot = pMenu->GetLastItem();
04242     ok = ok && pMenu->BuildCommand(OPTOKEN_QUICKSHAPE_NUMBERSIDES3, FALSE, pNumberRoot);
04243     ok = ok && pMenu->BuildCommand(OPTOKEN_QUICKSHAPE_NUMBERSIDES4, FALSE, pNumberRoot);
04244     ok = ok && pMenu->BuildCommand(OPTOKEN_QUICKSHAPE_NUMBERSIDES5, FALSE, pNumberRoot);
04245     ok = ok && pMenu->BuildCommand(OPTOKEN_QUICKSHAPE_NUMBERSIDES6, FALSE, pNumberRoot);
04246     ok = ok && pMenu->BuildCommand(OPTOKEN_QUICKSHAPE_NUMBERSIDES7, FALSE, pNumberRoot);
04247     ok = ok && pMenu->BuildCommand(OPTOKEN_QUICKSHAPE_NUMBERSIDES8, FALSE, pNumberRoot);
04248     ok = ok && pMenu->BuildCommand(OPTOKEN_QUICKSHAPE_NUMBERSIDES9, FALSE, pNumberRoot);
04249     ok = ok && pMenu->BuildCommand(OPTOKEN_QUICKSHAPE_NUMBERSIDES10, FALSE, pNumberRoot);
04250 
04251     return ok;
04252 #else
04253     return FALSE;
04254 #endif
04255 }
04256 
04257 
04258 
04259 /********************************************************************************************
04260 
04261 >   BOOL NodeRegularShape::IsARegularShape()
04262 
04263     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
04264     Created:    24/04/95
04265     Returns:    TRUE => This node is an instance of NodeRegularShape
04266                 FALSE => otherwise.
04267     Purpose:    Determine if a node is a QuickShape object.
04268 
04269 ********************************************************************************************/
04270 
04271 BOOL NodeRegularShape::IsARegularShape() const
04272 {
04273     return TRUE;
04274 }
04275 
04276 
04277 
04278 /********************************************************************************************
04279 
04280 >   double NodeRegularShape::GetMajorRadiusSize()
04281 
04282     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
04283     Created:    08/05/95
04284     Inputs:     -
04285     Outputs:    -
04286     Returns:    The length of the radius of the shape, ie the distance from the centre of the
04287                 shape to a primary point, or a stellation point, whichever is the longer.
04288     Purpose:    Gets the length of the longest radius of the shape.  
04289 
04290 ********************************************************************************************/
04291 double NodeRegularShape::GetMajorRadiusSize()
04292 {
04293     DocCoord OuterMajor = UTMajorAxes;
04294     if (IsStellated() && (GetStellRadiusToPrimary() > 1.0))
04295         PositionPointFromRatio(&OuterMajor, &UTMajorAxes, GetStellRadiusToPrimary());
04296 
04297     return UTCentrePoint.Distance(OuterMajor);
04298 }
04299 
04300 
04301 
04302 
04303 
04304 /********************************************************************************************
04305 >   BOOL NodeRegularShape::MakeRectangle(const INT32 Width, const INT32 Height, const INT32 CurvatureRadius)
04306 
04307     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
04308     Created:    23/05/95
04309     Inputs:     Width - the width of the rectangle
04310                 Height - the height of the rectangle
04311                 CurvatureRadius - the length of the curvature radius.  0 for no curvature
04312     Outputs:    Affects member variables of the shape
04313     Returns:    TRUE/FALSE for success/failure
04314     Purpose:    Called when importing rectangles.  Sets up a pre-created QuickShape to have
04315                 all the required features.  Note that it is centered at the origin.  Apply
04316                 furthur transforms as required
04317 ********************************************************************************************/
04318 BOOL NodeRegularShape::MakeRectangle(const INT32 Width, const INT32 Height, const INT32 CurvatureRadius)
04319 {
04320     ERROR3IF(CurvatureRadius < 0, "CurvatureRadius was -ve");
04321 
04322     // Set the flags
04323     SetNumSides(4);
04324     SetCircular(FALSE);
04325     SetStellated(FALSE);
04326 
04327     // To make life easy lets pretend we have a square
04328     const double SqrHalfHeight = ((double)Height/2)*((double)Height/2);
04329     const INT32 MajorLength = (INT32)(sqrt( SqrHalfHeight + SqrHalfHeight ));
04330 
04331     SetCentrePoint(DocCoord(0,0));
04332     SetMajorAxes(DocCoord(0, MajorLength));
04333     SetMinorAxes(DocCoord(MajorLength, 0));
04334 
04335     // Set the curvature
04336     if (CurvatureRadius < 1)
04337     {
04338         PrimaryCurvature = FALSE;   
04339         StellationCurvature = FALSE;
04340     }
04341     else
04342     {
04343         PrimaryCurvature = TRUE;    
04344         StellationCurvature = TRUE;
04345         PrimaryCurveToPrimary = ((double)CurvatureRadius) / ((double)MajorLength);
04346         StellCurveToStell = PrimaryCurveToPrimary;
04347     }
04348 
04349     // Reset the matrix
04350     Matrix Unity;                   // Default constructor gives unity
04351     SetTransformMatrix(&Unity);
04352 
04353     DocCoord NewMinor = DocCoord::PositionPointFromRatio(UTCentrePoint, UTMinorAxes, (double)Width/Height);
04354     SetMinorAxes(NewMinor);
04355 
04356     EmergencyFixShape();            // Bodge the shape if width/height are zero
04357 
04358     return TRUE;
04359 }
04360 
04361 
04362 
04363 /********************************************************************************************
04364 >   BOOL NodeRegularShape::MakeEllipse(const INT32 Width, const INT32 Height)
04365 
04366     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
04367     Created:    23/05/95
04368     Inputs:     Width - the width of the ellipse
04369                 Height - the height of the ellipse
04370     Outputs:    Affects member variables of the shape
04371     Returns:    TRUE/FALSE for success/failure
04372     Purpose:    Called when importing ellipse.  Sets up a pre-created QuickShape to have
04373                 all the required features.  Note that it is centered at the origin.  Apply
04374                 furthur transforms as required
04375 ********************************************************************************************/
04376 BOOL NodeRegularShape::MakeEllipse(const INT32 Width, const INT32 Height)
04377 {
04378     // Set the flags
04379     SetNumSides(6);
04380     SetCircular(TRUE);
04381     SetStellated(FALSE);
04382 
04383     SetCentrePoint(DocCoord(0,0));
04384     SetMajorAxes(DocCoord(0, Height));
04385     SetMinorAxes(DocCoord(Width, 0));
04386 
04387     // Reset the matrix
04388     Matrix Unity;                   // Default constructor gives unity
04389     SetTransformMatrix(&Unity);
04390 
04391     EmergencyFixShape();            // Bodge the shape if width/height are zero
04392 
04393     return TRUE;
04394 }
04395 
04396 /********************************************************************************************
04397 
04398 >   BOOL NodeRegularShape::WritePreChildrenNative(BaseCamelotFilter * pFilter)
04399     BOOL NodeRegularShape::WritePreChildrenWeb(BaseCamelotFilter * pFilter)
04400 
04401     Author:     Andy_Hayward (Xara Group Ltd) <camelotdev@xara.com>
04402     Created:    03/06/96
04403     Inputs:     pFilter - filter to use
04404     Returns:    Boolean value indicating success
04405     Purpose:    Writes this regular shape to the filter
04406 
04407 ********************************************************************************************/
04408 
04409 BOOL NodeRegularShape::WritePreChildrenNative(BaseCamelotFilter * pFilter)
04410 {
04411 #ifdef DO_EXPORT
04412     ERROR2IF(this == NULL, FALSE, "this == NULL");
04413     ERROR2IF(pFilter == NULL, FALSE, "pFilter == NULL");
04414     TRACEUSER( "Diccon", _T("Exporting Regular Shape\n"));
04415     String_256 Details = String_256((TCHAR*)(this->GetRuntimeClass()->m_lpszClassName));
04416     TRACEUSER( "Diccon", _T("(%s - 0x%x)\n"),(TCHAR*)Details,this);
04417     return CXaraFileRegularShape::WritePreChildrenNative(pFilter, this);
04418 #else
04419     return FALSE;
04420 #endif
04421 }
04422 
04423 BOOL NodeRegularShape::WritePreChildrenWeb(BaseCamelotFilter * pFilter)
04424 {
04425 #ifdef DO_EXPORT
04426     ERROR2IF(this == NULL, FALSE, "this == NULL");
04427     ERROR2IF(pFilter == NULL, FALSE, "pFilter == NULL");
04428 
04429     return CXaraFileRegularShape::WritePreChildrenWeb(pFilter, this);
04430 #else
04431     return FALSE;
04432 #endif
04433 }
04434 
04435   
04436 
04437 /********************************************************************************************
04438 >   void NodeRegularShape::DeleteCachedPath()
04439 
04440     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
04441     Created:    27/06/96
04442     Inputs:     -
04443     Returns:    -
04444     Purpose:    Deletes the shapes cached render path
04445 ********************************************************************************************/
04446 void NodeRegularShape::DeleteCachedPath()
04447 {
04448     if (CachedRenderPath != NULL)
04449     {
04450         delete CachedRenderPath;
04451         CachedRenderPath = NULL;
04452     }
04453 
04454     // if we have an applied brush attribute then flush the cache
04455     AttrBrushType* pBrush = NULL;
04456     FindAppliedAttribute(CC_RUNTIME_CLASS(AttrBrushType), (NodeAttribute**)&pBrush);
04457     if (pBrush && pBrush->GetBrushHandle() != BrushHandle_NoBrush)
04458         pBrush->FlushCache();
04459 
04460 
04461     PathCacheInvalid = TRUE;
04462 }
04463 
04464 /********************************************************************************************
04465 >   PathShape NodeRegularShape::GetPathShape()
04466 
04467     Author:     Graham_Walmsley (Xara Group Ltd) <camelotdev@xara.com>
04468     Created:    29/4/97
04469     Inputs:     -
04470     Returns:    An ENUM to say which shape the path is. Possible return
04471                 values are:
04472                 PATHSHAPE_RECTANGLE
04473                 PATHSHAPE_SQUARE
04474                 PATHSHAPE_ELLIPSE
04475                 PATHSHAPE_CIRCLE
04476                 PATHSHAPE_PATH  (the default)
04477 
04478     Purpose:    Gets a value to say which shape the path is. This value
04479                 is passed to RenderRegion::DrawPath.
04480 
04481   See Also:     RenderRegion::DrawPath, ImagemapRenderRegion::DrawPathToOutputDevice
04482 ********************************************************************************************/
04483 PathShape NodeRegularShape::GetPathShape()
04484 {
04485     //First test to see if the QuickShape is a rectangle
04486     if (IsARectangle() && !IsReformed())
04487     {
04488         //Yes it is
04489 
04490         //Now, is it a square?
04491         if (AxesAreEqual() && AxesArePerpendicular())
04492         {
04493             //Yes it is.
04494 
04495             //Has it been rotated?
04496             if (IsRotated())
04497                 return PATHSHAPE_SQUARE_ROTATED;
04498             else
04499                 return PATHSHAPE_SQUARE;
04500         }
04501         else
04502         {
04503             //No, it's not a square, so it's a normal rectangle.
04504 
04505             //Has it been rotated?
04506             if (IsRotated())
04507                 return PATHSHAPE_RECTANGLE_ROTATED;
04508             else
04509                 return PATHSHAPE_RECTANGLE;
04510         }
04511     }
04512 
04513     //Now let's find if the QuickShape is an ellipse
04514     if (IsCircular())
04515     {
04516         //Yes, it's an ellipse
04517 
04518         //Now, is it a circle?
04519         if (AxesAreEqual() && AxesArePerpendicular())
04520         {
04521             //Yes it is.
04522 
04523             return PATHSHAPE_CIRCLE;
04524         }
04525         else
04526         {
04527             //No, it's not a circle, just a normal ellipse
04528 
04529             //Has it been rotated?
04530             if (IsRotated())
04531                 return PATHSHAPE_ELLIPSE_ROTATED;
04532             else
04533                 return PATHSHAPE_ELLIPSE;
04534         }
04535     }
04536 
04537     //It's neither an ellipse or a rectangle.
04538     //So return the generic "Path" shape
04539     
04540     return PATHSHAPE_PATH;
04541 }
04542 
04543 /********************************************************************************************
04544 >   BOOL NodeRegularShape::IsRotated()
04545 
04546     Author:     Graham_Walmsley (Xara Group Ltd) <camelotdev@xara.com>
04547     Created:    29/4/97
04548     Inputs:     -
04549     Returns:    TRUE if the shape has been rotated
04550                 FALSE otherwise
04551 
04552     Purpose:    Finds if the shape has been rotated
04553 
04554                 The shape is defined as not being rotated if
04555                 a. It has been rotated by 0 degrees
04556                 b. It has been rotated by any multiple of (2PI/N) where
04557                     N is the number of sides of the shape.
04558 
04559                 The reasoning behind B is that, if a regular shape with
04560                 N sides is rotated by 2PI/N, it will appear to be an
04561                 unrotated regular shape.
04562 
04563                 For example, say you start with a rectangle, whose sides
04564                 are exactly parallel to the X and Y axes - that is, an unrotated
04565                 rectangle.
04566 
04567                 Then you rotated it by any multiple of 2PI/4 - that is, you rotate
04568                 it by 90, 180, 270 or 360 degrees.
04569 
04570                 In any case, the rectangle you end up with still has its sides
04571                 parallel to the X and Y axes - that is, it is still an unrotated
04572                 rectangle.
04573 
04574                 This is important in imagemaps: where clickable regions
04575                 can be defined for an unrotated rectangle (one with its sides
04576                 parallel to the X and Y axes) but not for a rotated rectangle.
04577 
04578   See Also:     NodeRegularShape::GetPathShape(), 
04579                 ImagemapRenderRegion::DrawPathToOutputDevice
04580 ********************************************************************************************/
04581 BOOL NodeRegularShape::IsRotated()
04582 {
04583     //First get the absolute angle by which this shape is rotated
04584     double dAngle=fabs(GetRotationAngle());
04585 
04586     //Now get the angle by which the shape is allowed to be rotated
04587     //and still defined as unrotated
04588     double dAllowedAngle=(double) ((2*PI)/GetNumSides());
04589 
04590     //Now check if the angle by which the shape is rotated is
04591     //equal to any multiple of dAllowedAngle
04592     for (double dCheckAngle=0; dCheckAngle<PI; dCheckAngle+=dAllowedAngle)
04593     {
04594         //If dCheckAngle==dAngle to within a given tolerance,
04595         //return FALSE
04596         double dDifference=fabs(dAngle-dCheckAngle);
04597 
04598         if (dDifference<QUICKSHAPE_ANGLE_TOLERANCE)
04599             return FALSE;
04600     }
04601 
04602     //No, the shape has not been rotated
04603     return TRUE;
04604     
04605 }
04606 
04607 /********************************************************************************************
04608 >   BOOL NodeRegularShape::AxesAreEqual()
04609 
04610     Author:     Graham_Walmsley (Xara Group Ltd) <camelotdev@xara.com>
04611     Created:    29/4/97
04612     Inputs:     -
04613     Returns:    TRUE if the major and minor axes are the same length
04614                 FALSE otherwise
04615 
04616     Purpose:    Finds if the major and minor axes are the same length
04617 
04618   See Also:     NodeRegularShape::GetPathShape()
04619 ********************************************************************************************/
04620 BOOL NodeRegularShape::AxesAreEqual()
04621 {
04622     //Get the centre point and major and minor axis points
04623     DocCoord dcCentre=GetCentrePoint();
04624     DocCoord dcMajor=GetMajorAxes();
04625     DocCoord dcMinor=GetMinorAxes();
04626 
04627     //Get the lengths of the major and minor axes
04628     double dMajorLength=dcCentre.Distance(dcMajor);
04629     double dMinorLength=dcCentre.Distance(dcMinor);
04630 
04631     //And return TRUE if the major and minor axes
04632     //are equal to within a set tolerance
04633     double dDifference=fabs(dMajorLength-dMinorLength);
04634 
04635     return (dDifference<QUICKSHAPE_RADIUS_TOLERANCE);
04636 
04637 }
04638 
04639 /********************************************************************************************
04640 >   BOOL NodeRegularShape::AxesArePerpendicular()
04641 
04642     Author:     Graham_Walmsley (Xara Group Ltd) <camelotdev@xara.com>
04643     Created:    29/4/97
04644     Inputs:     -
04645     Returns:    TRUE if the major and minor axes are perpendicular
04646                 FALSE otherwise
04647 
04648     Purpose:    Finds if the major and minor axes are perpendicular
04649 
04650   See Also:     NodeRegularShape::GetPathShape()
04651 ********************************************************************************************/
04652 BOOL NodeRegularShape::AxesArePerpendicular()
04653 {
04654     //Get the centre point and major and minor axis points
04655     DocCoord dcCentre=GetCentrePoint();
04656     DocCoord dcMajor=GetMajorAxes();
04657     DocCoord dcMinor=GetMinorAxes();
04658 
04659     //Now get a vector between dcCentre and dcMajor
04660     //For convenience, I won't actually create a vector class...I'll
04661     //just store the elements of the vector in longs
04662     INT32 lMajorVectorX=dcMajor.x-dcCentre.x;
04663     INT32 lMajorVectorY=dcMajor.y-dcCentre.y;
04664 
04665     //And get a vector between dcCentre and dcMinor
04666     INT32 lMinorVectorX=dcMinor.x-dcCentre.x;
04667     INT32 lMinorVectorY=dcMinor.y-dcCentre.y;
04668 
04669     //And now get the scalar product between them
04670     INT32 lScalarProduct=lMajorVectorX*lMinorVectorX+lMajorVectorY*lMinorVectorY;
04671                              
04672     //And return TRUE if the scalar product is zero to a set tolerance
04673     INT32 lDifference=labs(lScalarProduct);
04674 
04675     return (lDifference<QUICKSHAPE_SCALARPRODUCT_TOLERANCE);
04676 }
04677 
04678 
04679 
04680 /********************************************************************************************
04681 
04682 >   DocRect NodeRegularShape::ValidateExtend(const ExtendParams& ExtParams)
04683 
04684     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
04685     Created:    25/11/1999
04686     Inputs:     ExtParams       parameters describing the extension.
04687     Outputs:    
04688     Returns:    TRUE if this regular shape can be validly extended,
04689                 FALSE otherwise.
04690     Purpose:    Tests to see whether this shape's extend-centre is positioned so as to make
04691                 an extend operation irreversible.
04692     Errors:     
04693     See also:   
04694 
04695 ********************************************************************************************/
04696 DocRect NodeRegularShape::ValidateExtend(const ExtendParams& ExtParams)
04697 {
04698     DocCoord doccArray[1] = { FindExtendCentre() };
04699     DocRect drMinExtend = Extender::ValidateControlPoints(1, doccArray, ExtParams);
04700 
04701     // if we didn't invalidate the extension, we must call the base class
04702     // implementation, which will validate our children.
04703     if (drMinExtend.lo.x == INT32_MAX &&
04704         drMinExtend.lo.y == INT32_MAX &&
04705         drMinExtend.hi.x == INT32_MAX &&
04706         drMinExtend.hi.y == INT32_MAX)
04707         drMinExtend = Node::ValidateExtend(ExtParams);
04708 
04709     return drMinExtend;
04710 }
04711 
04712 
04713 
04714 /********************************************************************************************
04715 
04716 >   void NodeRegularShape::Extend(const ExtendParams& ExtParams)
04717 
04718     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
04719     Created:    25/11/1999
04720     Inputs:     ExtParams       parameters describing the extension.
04721     Outputs:    this NodeRegularShape will be extended in accordance with ExtParams.
04722     Returns:    
04723     Purpose:    Perform an Extend operation on this shape. Behaviour is as follows:
04724 
04725                 * the shape extends separately along each axis.
04726                 * if the shape is asked to stretch, it scales along the corresponding axes.
04727                 * if the shape is asked to extend, it is translated as a whole, as described
04728                                                                                 by ExtParams.
04729     Errors:     
04730     See also:   class Extender
04731 
04732 ********************************************************************************************/
04733 void NodeRegularShape::Extend(const ExtendParams& ExtParams)
04734 {
04735     // do the extension operations on ourself.
04736     TransformStretchObject(ExtParams);
04737     TransformTranslateObject(ExtParams);
04738 
04739     // do the base-class implementation to extend our children.
04740     Node::Extend(ExtParams);
04741 }
04742 
04743 
04744 
04745 /********************************************************************************************
04746 
04747 >   virtual INT32 NodeRegularShape::EstimateNodeComplexity (OpParam* details)
04748 
04749     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
04750     Created:    6/09/2000
04751 
04752     Inputs:     details     any data that should be used for the calculation
04753 
04754     Outputs:    -
04755 
04756     Returns:    an estimate of the nodes complexity
04757 
04758     Purpose:    This function estimates a complexity value for the node.  The complexity
04759                 value is based upon the total length of all paths in the node.
04760 
04761     See Also:   OpBlendNodes::DeterminBlendObjectsProcessorHit ()
04762 
04763 ********************************************************************************************/
04764 
04765 INT32 NodeRegularShape::EstimateNodeComplexity (OpParam* details)
04766 {
04767     if (CachedRenderPath)
04768     {
04769         return (CachedRenderPath->GetUsedSlots ());
04770     }
04771     else
04772     {
04773         return ((EdgePath1.GetUsedSlots ()) + (EdgePath2.GetUsedSlots ()));
04774     }
04775 }

Generated on Sat Nov 10 03:46:06 2007 for Camelot by  doxygen 1.4.4