00001 // $Id: nodeelip.cpp 1315 2006-06-14 09:51:34Z alex $ 00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE 00003 ================================XARAHEADERSTART=========================== 00004 00005 Xara LX, a vector drawing and manipulation program. 00006 Copyright (C) 1993-2006 Xara Group Ltd. 00007 Copyright on certain contributions may be held in joint with their 00008 respective authors. See AUTHORS file for details. 00009 00010 LICENSE TO USE AND MODIFY SOFTWARE 00011 ---------------------------------- 00012 00013 This file is part of Xara LX. 00014 00015 Xara LX is free software; you can redistribute it and/or modify it 00016 under the terms of the GNU General Public License version 2 as published 00017 by the Free Software Foundation. 00018 00019 Xara LX and its component source files are distributed in the hope 00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the 00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 00022 See the GNU General Public License for more details. 00023 00024 You should have received a copy of the GNU General Public License along 00025 with Xara LX (see the file GPL in the root directory of the 00026 distribution); if not, write to the Free Software Foundation, Inc., 51 00027 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 00028 00029 00030 ADDITIONAL RIGHTS 00031 ----------------- 00032 00033 Conditional upon your continuing compliance with the GNU General Public 00034 License described above, Xara Group Ltd grants to you certain additional 00035 rights. 00036 00037 The additional rights are to use, modify, and distribute the software 00038 together with the wxWidgets library, the wxXtra library, and the "CDraw" 00039 library and any other such library that any version of Xara LX relased 00040 by Xara Group Ltd requires in order to compile and execute, including 00041 the static linking of that library to XaraLX. In the case of the 00042 "CDraw" library, you may satisfy obligation under the GNU General Public 00043 License to provide source code by providing a binary copy of the library 00044 concerned and a copy of the license accompanying it. 00045 00046 Nothing in this section restricts any of the rights you have under 00047 the GNU General Public License. 00048 00049 00050 SCOPE OF LICENSE 00051 ---------------- 00052 00053 This license applies to this program (XaraLX) and its constituent source 00054 files only, and does not necessarily apply to other Xara products which may 00055 in part share the same code base, and are subject to their own licensing 00056 terms. 00057 00058 This license does not apply to files in the wxXtra directory, which 00059 are built into a separate library, and are subject to the wxWindows 00060 license contained within that directory in the file "WXXTRA-LICENSE". 00061 00062 This license does not apply to the binary libraries (if any) within 00063 the "libs" directory, which are subject to a separate license contained 00064 within that directory in the file "LIBS-LICENSE". 00065 00066 00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS 00068 ---------------------------------------------- 00069 00070 Subject to the terms of the GNU Public License (see above), you are 00071 free to do whatever you like with your modifications. However, you may 00072 (at your option) wish contribute them to Xara's source tree. You can 00073 find details of how to do this at: 00074 http://www.xaraxtreme.org/developers/ 00075 00076 Prior to contributing your modifications, you will need to complete our 00077 contributor agreement. This can be found at: 00078 http://www.xaraxtreme.org/developers/contribute/ 00079 00080 Please note that Xara will not accept modifications which modify any of 00081 the text between the start and end of this header (marked 00082 XARAHEADERSTART and XARAHEADEREND). 00083 00084 00085 MARKS 00086 ----- 00087 00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara 00089 designs are registered or unregistered trademarks, design-marks, and/or 00090 service marks of Xara Group Ltd. All rights in these marks are reserved. 00091 00092 00093 Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK. 00094 http://www.xara.com/ 00095 00096 =================================XARAHEADEREND============================ 00097 */ 00098 // NodeEllipse - The Ellipse Class 00099 00100 00101 /* 00102 */ 00103 00104 00105 #include "camtypes.h" 00106 #include "nodeelip.h" 00107 00108 //#include "app.h" 00109 #include "aw_eps.h" 00110 #include "blobs.h" 00111 //#include "docview.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00112 //#include "opsmpshp.h" 00113 //#include "osrndrgn.h" 00114 //#include "rik.h" 00115 00116 DECLARE_SOURCE( "$Revision: 1315 $" ); 00117 00118 // Declare this class and give my name for bad memory handling 00119 CC_IMPLEMENT_DYNCREATE(NodeEllipse, NodeSimpleShape) 00120 00121 // Declare smart memory handling in Debug builds 00122 #define new CAM_DEBUG_NEW 00123 00124 00125 /*********************************************************************************************** 00126 00127 > NodeEllipse::NodeEllipse( Node* ContextNode, 00128 AttachNodeDirection Direction, 00129 BOOL Locked, 00130 BOOL Mangled, 00131 BOOL Marked, 00132 BOOL Selected 00133 ) 00134 00135 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00136 Created: 1/6/94 00137 Inputs: ContextNode - Pointer to a node which this node is to be attached to. 00138 Direction - Specifies the direction in which the node is to be attached to the 00139 ContextNode. 00140 BoundingRect - The Bounding rectangle 00141 Purpose: This constructor initialises the nodes flags and links it to ContextNode in the 00142 direction specified by Direction. All neccesary tree links are updated. 00143 Note: SetUpPath() must be called before the NodeRect is in a state in which it can be 00144 used. 00145 SeeAlso: SetUpPath 00146 Errors: An assertion error will occur if ContextNode is NULL 00147 00148 ***********************************************************************************************/ 00149 00150 NodeEllipse::NodeEllipse( Node* ContextNode, 00151 AttachNodeDirection Direction, 00152 BOOL Locked, 00153 BOOL Mangled, 00154 BOOL Marked, 00155 BOOL Selected 00156 ):NodeSimpleShape(ContextNode, Direction, Locked, Mangled, Marked, Selected ) 00157 { 00158 } 00159 00160 /********************************************************************************************* 00161 00162 > NodeEllipse::NodeEllipse() 00163 00164 Author: Mario_Shamtani (Xara Group Ltd) <camelotdev@xara.com> 00165 Created: 1/6/94 00166 Purpose: This constructor creates a NodeRect linked to no other with all status 00167 flags false and an uninitialized bounding rectangle. 00168 Note: SetUpPath() must be called before the NodeRect is in a state in which it can be 00169 used. 00170 SeeAlso: SetUpPath 00171 00172 **********************************************************************************************/ 00173 /* Technical Notes: 00174 00175 The default constructor is required so that SimpleCopy will work 00176 */ 00177 00178 NodeEllipse::NodeEllipse(): NodeSimpleShape() 00179 { 00180 } 00181 00182 /*********************************************************************************************** 00183 00184 > virtual Node* NodeEllipse::SimpleCopy() 00185 00186 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00187 Created: 26/5/93 00188 Returns: Pointer to a Node 00189 Purpose: Makes a copy of all the data in the node 00190 00191 ***********************************************************************************************/ 00192 00193 Node* NodeEllipse::SimpleCopy() 00194 { 00195 // Make a new NodeSimpleShape and then copy things into it 00196 NodeEllipse* NodeCopy = new NodeEllipse(); 00197 if (NodeCopy) 00198 CopyNodeContents(NodeCopy); 00199 00200 return NodeCopy; 00201 } 00202 00203 00204 /******************************************************************************************** 00205 00206 > virtual String NodeEllipse::Describe(BOOL Plural, BOOL Verbose = TRUE) 00207 00208 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00209 Created: 1/6/94 00210 Inputs: Plural: Flag indicating if the string description should be plural or 00211 singular. 00212 Retuns: Description of the object 00213 Purpose: To return a description of the NodeRect object in either the singular or the 00214 plural. This method is called by the DescribeRange method. 00215 The description will always begin with a lower case letter. 00216 Errors: A resource exception will be thrown if a problem occurs when loading the 00217 string resource. 00218 00219 ********************************************************************************************/ 00220 00221 String NodeEllipse::Describe(BOOL Plural, BOOL Verbose) 00222 { 00223 if (Plural) 00224 return(String(_R(IDS_ELLIPSE_DESCRP))); 00225 else 00226 return(String(_R(IDS_ELLIPSE_DESCRS))); 00227 } 00228 00229 /******************************************************************************************** 00230 00231 > void NodeEllipse::PreExportRender(RenderRegion* pRegion) 00232 00233 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00234 Created: 17/08/94 00235 Inputs: pRegion - the render region we are exporting to. 00236 Purpose: Output data required to mark this object as an ellipse, as opposed to an 00237 arbitrary path. 00238 00239 ********************************************************************************************/ 00240 00241 void NodeEllipse::PreExportRender(RenderRegion* pRegion) 00242 { 00243 #ifdef DO_EXPORT 00244 if (pRegion->IsKindOf(CC_RUNTIME_CLASS(ArtWorksEPSRenderRegion))) 00245 { 00246 // Output "ArtWorks ellipse" token 00247 EPSExportDC *pDC = (EPSExportDC *) pRegion->GetRenderDC(); 00248 00249 // Output the 3 coords defining the ellipse's bounding parallelogram 00250 pDC->OutputCoord(Parallel[0]); 00251 pDC->OutputCoord(Parallel[1]); 00252 pDC->OutputCoord(Parallel[2]); 00253 00254 // And the token itself 00255 pDC->OutputToken(_T("ae")); 00256 pDC->OutputNewLine(); 00257 } 00258 #endif 00259 } 00260 00261 00262 00263 00264 /*********************************************************************************************** 00265 00266 > virtual void NodeEllipse::CreateShape(DocRect NewRect) 00267 00268 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00269 Created: 1/6/94 00270 Inputs: DocRect - representing the rectangle to create the shape in 00271 Purpose: Creates an Ellipse using a path that fills the rectangle specified. 00272 00273 ***********************************************************************************************/ 00274 00275 void NodeEllipse::CreateShape(DocRect NewRect) 00276 { 00277 // Copy the rectangle into the parallelogram 00278 Parallel[0] = DocCoord(NewRect.lo.x, NewRect.hi.y); 00279 Parallel[1] = DocCoord(NewRect.hi.x, NewRect.hi.y); 00280 Parallel[2] = DocCoord(NewRect.hi.x, NewRect.lo.y); 00281 Parallel[3] = DocCoord(NewRect.lo.x, NewRect.lo.y); 00282 00283 // Get an array to put the 12 different coords needed to specify an ellipse 00284 DocCoord NewCoords[12]; 00285 00286 // Calculate the 3 coordinates along each side of the parallelogram 00287 CalcEllipseEdge(Parallel[0], Parallel[1], &NewCoords[11], &NewCoords[0], &NewCoords[1]); 00288 CalcEllipseEdge(Parallel[1], Parallel[2], &NewCoords[2], &NewCoords[3], &NewCoords[4]); 00289 CalcEllipseEdge(Parallel[2], Parallel[3], &NewCoords[5], &NewCoords[6], &NewCoords[7]); 00290 CalcEllipseEdge(Parallel[3], Parallel[0], &NewCoords[8], &NewCoords[9], &NewCoords[10]); 00291 00292 // build a path 00293 InkPath.ClearPath(); 00294 InkPath.FindStartOfPath(); 00295 00296 // Start at bottom left corner 00297 PathFlags NewFlags; 00298 NewFlags.IsRotate = TRUE; 00299 InkPath.InsertMoveTo(NewCoords[0], &NewFlags); 00300 InkPath.InsertCurveTo(NewCoords[1], NewCoords[2], NewCoords[3], &NewFlags); 00301 InkPath.InsertCurveTo(NewCoords[4], NewCoords[5], NewCoords[6], &NewFlags); 00302 InkPath.InsertCurveTo(NewCoords[7], NewCoords[8], NewCoords[9], &NewFlags); 00303 InkPath.InsertCurveTo(NewCoords[10], NewCoords[11], NewCoords[0], &NewFlags); 00304 00305 // Close the path properly 00306 InkPath.CloseSubPath(); 00307 } 00308 00309 00310 00311 00312 /*********************************************************************************************** 00313 00314 > virtual void NodeEllipse::UpdateShape() 00315 00316 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00317 Created: 1/6/94 00318 Purpose: Updates Ellipse node to fit the current parallelogram 00319 00320 ***********************************************************************************************/ 00321 00322 void NodeEllipse::UpdateShape() 00323 { 00324 // make sure the path seems to have the correct number of coords in it 00325 ENSURE(InkPath.GetNumCoords()==13, "NodeEllipse::UpdateShape found its path corrupt" ); 00326 00327 // Get the array of coords in the path 00328 DocCoord* Coords = InkPath.GetCoordArray(); 00329 00330 // Update them to what we now have 00331 CalcEllipseEdge(Parallel[0], Parallel[1], &Coords[11], &Coords[0], &Coords[1]); 00332 CalcEllipseEdge(Parallel[1], Parallel[2], &Coords[2], &Coords[3], &Coords[4]); 00333 CalcEllipseEdge(Parallel[2], Parallel[3], &Coords[5], &Coords[6], &Coords[7]); 00334 CalcEllipseEdge(Parallel[3], Parallel[0], &Coords[8], &Coords[9], &Coords[10]); 00335 Coords[12] = Coords[0]; 00336 } 00337 00338 00339 /******************************************************************************************** 00340 00341 > void NodeEllipse::CalcEllipseEdge(DocCoord& P0, DocCoord& P1, DocCoord* NewCoordA, 00342 DocCoord* NewCoordB, DocCoord* NewCoordC) 00343 00344 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00345 Created: 1/6/94 00346 Inputs: P0 - The First Corner of the parallelogram 00347 P1 - The Second Corner of the parallelogram 00348 Outputs: NewCoordA - The coord of the Bezier control point closest to P0 00349 NewCoordB - The coord of the Bezier Endpoint that is midway between P1 & P1 00350 NewCoordC - The coord of the Bezier control point closest to P1 00351 Purpose: This function is used to fit an Ellipse inside a parallelogram using Bezier 00352 Curves. Along each side of the parallelogram there will be 3 coordinates (an 00353 Endpoint and 2 control points). This function calculate the 3 coordinates along 00354 a single side of the parallelogram (to calc all the control points the function 00355 would need to be called 4 times). The Coords P1 and P1 are assumed to be 00356 adjacent coordinates of the parallelogram. 00357 The maths for calculating coordinates for Rounded Rectangles is very similar. 00358 I have made optimisations in this function as not as much maths is needed. 00359 For a full description of the maths used here see the document 00360 Camelot/doc/ellipse.doc 00361 00362 ********************************************************************************************/ 00363 00364 void NodeEllipse::CalcEllipseEdge(const DocCoord& P0, const DocCoord& P1, DocCoord* NewCoordA, 00365 DocCoord* NewCoordB, DocCoord* NewCoordC) 00366 { 00367 // Do the maths. This is described in the document camelot\docs\ellipse.doc 00368 // Find the length of the first side (pythag) 00369 INT32 dx = P1.x - P0.x; 00370 INT32 dy = P1.y - P0.y; 00371 //double SideLength = sqrt(dx*dx + dy*dy); 00372 //ENSURE(SideLength!=0.0, "CalcEllipseEdge was thinking of doing a div 0!"); 00373 00374 // This would be different if we were calculating a rounded rectangle 00375 //double ArcRadius = SideLength / 2.0; 00376 //double ControlDist = ArcRadius/(SideLength*2.2336); 00377 // This is equivalent to the above 2 lines, only less maths is needed 00378 // (ie none as the compiler should do it) 00379 double ControlDist = 1.0 / (2 * 2.2336); 00380 00381 // Find the control point closest to P0 00382 NewCoordA->x = (INT32) (P0.x + (dx * ControlDist)); 00383 NewCoordA->y = (INT32) (P0.y + (dy * ControlDist)); 00384 00385 // Find the mid point of the side, for the middle control point 00386 NewCoordB->x = (INT32) (P0.x + (dx / 2)); 00387 NewCoordB->y = (INT32) (P0.y + (dy / 2)); 00388 00389 // Find the Control point closest to p1 00390 NewCoordC->x = (INT32) (P1.x - dx * ControlDist); 00391 NewCoordC->y = (INT32) (P1.y - dy * ControlDist); 00392 } 00393 00394 00395 00396 00397 /******************************************************************************************** 00398 00399 > DocRect NodeEllipse::GetBlobBoundingRect() 00400 00401 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00402 Created: 4/11/94 00403 Returns: The bounding rect of the Ellipse and its blobs 00404 Purpose: Calculates the ellipses bounding rect along with its blobs 00405 00406 ********************************************************************************************/ 00407 00408 DocRect NodeEllipse::GetBlobBoundingRect() 00409 { 00410 #if !defined(EXCLUDE_FROM_RALPH) 00411 // Find the paths bounding rectangle 00412 DocRect ShapeRect = GetBoundingRect(); 00413 DocRect Rect(Parallel[0], Parallel[0]); 00414 Rect.IncludePoint(Parallel[1]); 00415 Rect.IncludePoint(Parallel[2]); 00416 Rect.IncludePoint(Parallel[3]); 00417 00418 // Find the blob manager 00419 BlobManager* pBlobMgr = GetApplication()->GetBlobManager(); 00420 00421 // Get a rect to put the extra rectangle on 00422 DocRect BlobRect; 00423 00424 // Get the rect round a blob in the corner of the ellipse and add it to the total 00425 DocCoord Corner = Rect.HighCorner(); 00426 pBlobMgr->GetBlobRect(Corner, &BlobRect); 00427 Rect = Rect.Union(BlobRect); 00428 00429 // and the same with the other corner 00430 Corner = Rect.LowCorner(); 00431 pBlobMgr->GetBlobRect(Corner, &BlobRect); 00432 Rect = Rect.Union(BlobRect); 00433 00434 // and union it with the rect of the shape or things like Linewidth get in the way 00435 Rect = Rect.Union(ShapeRect); 00436 00437 // Make sure we include the Bounds of our children 00438 IncludeChildrensBoundingRects(&Rect); 00439 00440 // return the rectangle with the blobs included 00441 return Rect; 00442 #else 00443 return DocRect(0,0,0,0); 00444 #endif 00445 } 00446 00447 00448 00449 00450 /******************************************************************************************** 00451 00452 > virtual UINT32 NodeEllipse::GetNodeSize() const 00453 00454 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00455 Created: 1/6/94 00456 Returns: The size of the node in bytes 00457 Purpose: For finding the size of the node 00458 SeeAlso: Node::GetSubtreeSize 00459 00460 ********************************************************************************************/ 00461 00462 UINT32 NodeEllipse::GetNodeSize() const 00463 { 00464 return (sizeof(NodeEllipse)); 00465 } 00466 00467 00468 00469 00470 /******************************************************************************************** 00471 00472 > virtual void NodeEllipse::HandleBlobDrag(DocCoord& PointerPos, Spread* pSpread, INT32 FixedCorner) 00473 00474 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00475 Created: 2/6/94 00476 Inputs: PointerPos - The position the mouse pointer clicked 00477 pSpread - the spread that the click was on 00478 FixedCorner - The corner of the parallelogram that will stay fixed during 00479 the drag 00480 Purpose: When a drag is started on one of the paths blobs this is called. It tries to 00481 fire up an operation that will perform a drag of all the selected points, 00482 including all the EORing of the relavent parts of the curve. If it fails it 00483 will inform the user and not bother. 00484 00485 ********************************************************************************************/ 00486 00487 void NodeEllipse::HandleBlobDrag(DocCoord& PointerPos, Spread* pSpread, INT32 FixedCorner) 00488 { 00489 /* OpEditEllipse* pOp = new OpEditEllipse; 00490 if (pOp==NULL) 00491 { 00492 // Failed to get the memory to do the job 00493 if (IsUserName( "Rik" )) TRACE( _T("The Node Ellipse Edit Operation failed to start\n") ); 00494 00495 // Inform the person doing the clicking that life is not looking so good 00496 InformError(); 00497 } 00498 else 00499 { 00500 // Start the drag operation and pass in the Anchor Point to the operation 00501 pOp->DoDrag(PointerPos, pSpread, this, FixedCorner); 00502 }*/ 00503 } 00504 00505 00506