// $Id: ndbrshpt.cpp 751 2006-03-31 15:43:49Z alex $ /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE ================================XARAHEADERSTART=========================== Xara LX, a vector drawing and manipulation program. Copyright (C) 1993-2006 Xara Group Ltd. Copyright on certain contributions may be held in joint with their respective authors. See AUTHORS file for details. LICENSE TO USE AND MODIFY SOFTWARE ---------------------------------- This file is part of Xara LX. Xara LX is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. Xara LX and its component source files are distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Xara LX (see the file GPL in the root directory of the distribution); if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ADDITIONAL RIGHTS ----------------- Conditional upon your continuing compliance with the GNU General Public License described above, Xara Group Ltd grants to you certain additional rights. The additional rights are to use, modify, and distribute the software together with the wxWidgets library, the wxXtra library, and the "CDraw" library and any other such library that any version of Xara LX relased by Xara Group Ltd requires in order to compile and execute, including the static linking of that library to XaraLX. In the case of the "CDraw" library, you may satisfy obligation under the GNU General Public License to provide source code by providing a binary copy of the library concerned and a copy of the license accompanying it. Nothing in this section restricts any of the rights you have under the GNU General Public License. SCOPE OF LICENSE ---------------- This license applies to this program (XaraLX) and its constituent source files only, and does not necessarily apply to other Xara products which may in part share the same code base, and are subject to their own licensing terms. This license does not apply to files in the wxXtra directory, which are built into a separate library, and are subject to the wxWindows license contained within that directory in the file "WXXTRA-LICENSE". This license does not apply to the binary libraries (if any) within the "libs" directory, which are subject to a separate license contained within that directory in the file "LIBS-LICENSE". ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS ---------------------------------------------- Subject to the terms of the GNU Public License (see above), you are free to do whatever you like with your modifications. However, you may (at your option) wish contribute them to Xara's source tree. You can find details of how to do this at: http://www.xaraxtreme.org/developers/ Prior to contributing your modifications, you will need to complete our contributor agreement. This can be found at: http://www.xaraxtreme.org/developers/contribute/ Please note that Xara will not accept modifications which modify any of the text between the start and end of this header (marked XARAHEADERSTART and XARAHEADEREND). MARKS ----- Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara designs are registered or unregistered trademarks, design-marks, and/or service marks of Xara Group Ltd. All rights in these marks are reserved. Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK. http://www.xara.com/ =================================XARAHEADEREND============================ */ // implementation of NodeBrushPath #include "camtypes.h" #include "ndbrshpt.h" #include "pathproc.h" #include "ndbrshmk.h" #include "nodebrsh.h" CC_IMPLEMENT_DYNCREATE(NodeBrushPath, NodeBlendPath); /********************************************************************************************* > NodeBrushPath::NodeBrushPath() Author: Diccon_Yamanaka (Xara Group Ltd) Created: 6/10/99 Purpose: This constructor creates a NodeBrushPath linked to no other, with all status flags false and an uninitialised bounding rectangle. **********************************************************************************************/ NodeBrushPath::NodeBrushPath(): NodeBlendPath() { m_pCachedPointsAtDistance = NULL; // Reuse the "Destroy cache" call DestroyCachedInformation(); m_bDrawingBrush = FALSE; m_pProcessPath = NULL; } /*********************************************************************************************** > void NodeBrushPath::NodeBrushPath ( Node* ContextNode, AttachNodeDirection Direction, BOOL Locked = FALSE, BOOL Mangled = FALSE, BOOL Marked = FALSE, BOOL Selected = FALSE, ) Author: Diccon_Yamanaka (Xara Group Ltd) Created: 6/10/99 Inputs: ContextNode: Pointer to a node which this node is to be attached to. Direction: Specifies the direction in which this node is to be attached to the ContextNode. The values this variable can take are as follows: PREV : Attach node as a previous sibling of the context node NEXT : Attach node as a next sibling of the context node FIRSTCHILD: Attach node as the first child of the context node LASTCHILD : Attach node as a last child of the context node The remaining inputs specify the status of the node: Locked: Is node locked ? Mangled: Is node mangled ? Marked: Is node marked ? Selected: Is node selected ? Outputs: - Returns: - Purpose: This method initialises the node and links it to ContextNode in the direction specified by Direction. All necessary tree links are updated. Errors: An assertion error will occur if ContextNode is NULL ***********************************************************************************************/ NodeBrushPath::NodeBrushPath(Node* ContextNode, AttachNodeDirection Direction, BOOL Locked, BOOL Mangled, BOOL Marked, BOOL Selected ):NodeBlendPath(ContextNode, Direction, Locked, Mangled, Marked, Selected) { m_pCachedPointsAtDistance = NULL; // Reuse the "Destroy cache" call DestroyCachedInformation(); m_bDrawingBrush = FALSE; m_pProcessPath = NULL; } /********************************************************************************************* > NodeBrushPath::~NodeBrushPath() Author: Diccon_Yamanaka (Xara Group Ltd) Created: 6/10/99 Purpose: Destructor for NodeBrushPath. **********************************************************************************************/ NodeBrushPath::~NodeBrushPath() { // Reuse the "Destroy cache" call DestroyCachedInformation(); if (m_pProcessPath != NULL) { delete m_pProcessPath; m_pProcessPath = NULL; } } /*********************************************************************************************** > virtual Node* NodeBrushPath::SimpleCopy() Author: Diccon_Yamanaka (Xara Group Ltd) Created: 6/10/99 Returns: Pointer to a Node Purpose: Makes a copy of all the data in the node ***********************************************************************************************/ Node* NodeBrushPath::SimpleCopy() { NodeBrushPath* NodeCopy = new NodeBrushPath(); if (NodeCopy) CopyNodeContents(NodeCopy); return NodeCopy; } /*********************************************************************************************** > void NodeBrushPath::CopyNodeContents(NodeBrushPath* NodeCopy) Author: Diccon_Yamanaka (Xara Group Ltd) Created: 6/10/99 Inputs: NodeCopy - The node to copy Purpose: Copies the data in the node by first calling the base class to get it to copy its stuff, and then copying its own stuff Scope: protected SeeAlso: NodeRenderableInk::CopyNodeContents ***********************************************************************************************/ void NodeBrushPath::CopyNodeContents( NodeBrushPath* NodeCopy) { NodePath::CopyNodeContents( NodeCopy ); //Copy contents specific to derived class here } /*********************************************************************************************** > void NodeBrushPath::PolyCopyNodeContents(NodeRenderable* pNodeCopy) Author: Phil_Martin (Xara Group Ltd) Created: 18/12/2003 Outputs: - Purpose: Polymorphically copies the contents of this node to another Errors: An assertion failure will occur if NodeCopy is NULL Scope: protected ***********************************************************************************************/ void NodeBrushPath::PolyCopyNodeContents(NodeRenderable* pNodeCopy) { ENSURE(pNodeCopy, "Trying to copy a node's contents into a NULL node"); ENSURE(IS_A(pNodeCopy, NodeBrushPath), "PolyCopyNodeContents given wrong dest node type"); if (IS_A(pNodeCopy, NodeBrushPath)) CopyNodeContents((NodeBrushPath*)pNodeCopy); } /******************************************************************************************** > virtual BOOL NodeBrushPath::WritePreChildrenWeb(BaseCamelotFilter* pFilter) Author: Diccon_Yamanaka (Xara Group Ltd) Created: 7/10/99 Inputs: pFilter = ptr to the filter Returns: TRUE if record is written, FALSE if not Purpose: Writes the nodebrushpath path record to the filter SeeAlso: - ********************************************************************************************/ BOOL NodeBrushPath::WritePreChildrenWeb(BaseCamelotFilter* pFilter) { ERROR2IF(pFilter == NULL,FALSE,"NULL filter param"); BOOL ok = TRUE; /* INT32 NumCoords = InkPath.GetNumCoords(); INT32 RecordSize = sizeof(INT32)+(sizeof(PathVerb)*NumCoords)+(sizeof(DocCoord)*NumCoords); CamelotFileRecord Rec(pFilter,TAG_BLEND_PATH,RecordSize); BOOL ok = Rec.Init(); if (ok) ok = Rec.WritePath(&InkPath); if (ok) ok = pFilter->Write(&Rec); if (ok) { CamelotFileRecord FilledRec(pFilter, TAG_NODEBLENDPATH_FILLED, sizeof(INT32)); ok = FilledRec.Init(); if (ok) { INT32 Filled = InkPath.IsFilled; ok = FilledRec.WriteINT32(Filled); if (ok) ok = pFilter->Write(&FilledRec); } } if (!ok) pFilter->GotError(_R(IDE_FILE_WRITE_ERROR)); */ return ok; } /******************************************************************************************** > virtual BOOL NodeBrushPath::WritePreChildrenNative(BaseCamelotFilter* pFilter) Author: Diccon_Yamanaka (Xara Group Ltd) Created: 7/10/99 Inputs: pFilter = ptr to the filter Returns: TRUE if record is written, FALSE if not Purpose: Writes the nodebrushpath path record to the filter SeeAlso: - ********************************************************************************************/ BOOL NodeBrushPath::WritePreChildrenNative(BaseCamelotFilter* pFilter) { return WritePreChildrenWeb(pFilter); } /******************************************************************************************** > void NodeBrushPath::SetPointAtDistance(MILLIPOINT Distance, DocCoord* pPoint) Author: Diccon_Yamanaka (Xara Group Ltd) Created: 7/10/99 Inputs: Distance = a length along the path Outputs: pPoint = the coordinate of the point that distance along the path Returns: - Purpose: Sets the coordinate of a point a certain distance along this path in the cached points map ********************************************************************************************/ void NodeBrushPath::SetPointAtDistance(MILLIPOINT Distance, DocCoord Point) { CPathPointInfo PointInfo; if (m_pCachedPointsAtDistance == NULL) { m_pCachedPointsAtDistance = new CMap; // if (m_pCachedPointsAtDistance != NULL) // m_pCachedPointsAtDistance->InitHashTable(1277); // Init hash table size to a suitably large prime number } PointInfo.m_Point = Point; if (m_pCachedPointsAtDistance != NULL) m_pCachedPointsAtDistance->SetAt(Distance,PointInfo); } /******************************************************************************************** > INT32 NodeBrushPath::GetNumberOfSteps() Author: Diccon_Yamanaka (Xara Group Ltd) Created: 7/10/99 Inputs: - Outputs: - Returns: the number of steps in the nodebrushpath, given the step distance Purpose: as above ********************************************************************************************/ INT32 NodeBrushPath::GetNumberOfSteps() { return m_NumSteps; } /******************************************************************************************** > void NodeBrushPath::SetNumberOfSteps(INT32 Steps) Author: Diccon_Yamanaka (Xara Group Ltd) Created: 7/10/99 Inputs: Steps - the number to set Outputs: - Returns: - Purpose: sets the number of steps in the nodeblendpath ********************************************************************************************/ void NodeBrushPath::SetNumberOfSteps(INT32 Steps) { m_NumSteps = Steps; } /******************************************************************************************** > void NodeBrushPath::StartedBrush() Author: Diccon_Yamanaka (Xara Group Ltd) Created: 7/10/99 Inputs: - Outputs: - Returns: - Purpose: informs the nodebrushpath that the brush is being drawn ********************************************************************************************/ void NodeBrushPath::StartedBrush() { // ResetPathProcCache(); m_bDrawingBrush = TRUE; } /******************************************************************************************** > void NodeBrushPath::StoppedBrush() Author: Diccon_Yamanaka (Xara Group Ltd) Created: 7/10/99 Inputs: - Outputs: - Returns: - Purpose: informs the nodebrushpath that the brush has finished being drawn ********************************************************************************************/ void NodeBrushPath::StoppedBrush() { m_bDrawingBrush = FALSE; ResetPathProcCache(); if (m_pProcessPath != NULL) { delete m_pProcessPath; m_pProcessPath = NULL; } } /******************************************************************************************** > DocRect NodeBrushPath::GetBoundingRect(BOOL DontUseAttrs=FALSE, BOOL HitTest=FALSE) Author: Diccon_Yamanaka (Xara Group Ltd) Created: 19/9/99 Inputs: DontUseAttrs - TRUE if you don't want to use the nodes attrs to calculate the bounding rect (defaults will be used). Defaults to FALSE. HitTest - TRUE if being called during HitTest Returns: bounding rectangle of the inkpath Purpose: Returns the bounding rectangle of the coordinates of the path ********************************************************************************************/ DocRect NodeBrushPath::GetBoundingRect() { //TRACEUSER( "Diccon", _T("Getting BRect, currently %d\n"), IsBoundingRectValid); return NodePath::GetBoundingRect(); } /******************************************************************************************** > void NodeBrushPath::AddPointToBoundingRect(DocCoord Point) Author: Diccon_Yamanaka (Xara Group Ltd) Created: 19/9/99 Inputs: Point - coordinate to include in the bounding rect Returns: - Purpose: So that we can generate the bounding rect of the path as it is drawn this function allows us to add a single point to the bounding rectangle ********************************************************************************************/ void NodeBrushPath::IncludePointInBoundingRect(DocCoord Point) { BoundingRectangle.IncludePoint(Point); } /******************************************************************************************** > void NodeBrushPath::Render( RenderRegion* pRender ) Author: Diccon_Yamanaka (Xara Group Ltd) Created: 9/11/99 Inputs: pRender - A Pointer to the current RenderRegion Purpose: If the brush is selected then the path is rendered, otherwise not ********************************************************************************************/ void NodeBrushPath::Render( RenderRegion* pRender ) { pRender -> DrawPath( &InkPath ); } /******************************************************************************************** > void NodeBrushPath::RenderObjectBlobs(RenderRegion* pRender) Author: Diccon_Yamanaka (Xara Group Ltd) Created: 12/11/99 Inputs: pRender - The region to render the blobs into Purpose: Draws the actual path, so that it is only seen when selected ********************************************************************************************/ void NodeBrushPath::RenderObjectBlobs(RenderRegion* pRender) { pRender -> DrawPath( &InkPath ); } /******************************************************************************************** > void NodeBrushPath::RenderTinyBlobs(RenderRegion* pRender) Author: Diccon_Yamanaka (Xara Group Ltd) Created: 12/11/99 Inputs: pRender - The region to render the blobs into Purpose: Draws the actual path, so that it is only seen when selected ********************************************************************************************/ void NodeBrushPath::RenderTinyBlobs(RenderRegion* pRender) { //pRender -> DrawPath( &InkPath ); } /******************************************************************************************** > void NodeBrushPath::RenderEorDrag( RenderRegion* pRender ) Author: Diccon_Yamanaka (Xara Group Ltd) Created: 9/11/99 Inputs: pRender - A Pointer to the current RenderRegion Purpose: Renders a version of the path for EORed dragging of shapes. SeeAlso: NodePath::Render; NodeRenderableInk::RenderEorDrag ********************************************************************************************/ void NodeBrushPath::RenderEorDrag( RenderRegion* pRender ) { pRender -> DrawPath( &InkPath ); } /******************************************************************************************** > virtual void NodeBrushPath::Transform( TransformBase& Trans ) Author: Diccon_Yamanaka (Xara Group Ltd) Created: 28/11/99 Inputs: Trans - The transform to be applied to the path Purpose: Will Transform all the coords in the path with the transform provided SeeAlso: NodeRenderableInk::Transform() ********************************************************************************************/ void NodeBrushPath::Transform(TransformBase &Trans) { // Change all the coords Trans.Transform( (DocCoord*)InkPath.GetCoordArray(), InkPath.GetNumCoords() ); // and keep the bounding rectangle up to date. InvalidateBoundingRect(); // Transform all the children... TransformChildren(Trans); // clear out the cache DestroyCachedInformation(); // as we are going to need to recalculate all the points try // to get the path processor back in action, don't worry if it fails though if (InitialisePathProcessor()) { // we got it, so tell the NBM to ask for the cache Node* pParent = this->FindParent(); if (pParent != NULL) { NodeBrushMaker* pMaker = (NodeBrushMaker*)pParent->FindFirstChild(CC_RUNTIME_CLASS(NodeBrushMaker)); if (pMaker != NULL) pMaker->SetUsePathCache(FALSE); } else { delete m_pProcessPath; m_pProcessPath = NULL; } } } /******************************************************************************************** > BOOL NodeBrushPath::GetPointAtDistance(MILLIPOINT Distance, DocCoord* pPoint, double* pTangent, BOOL UseCache = FALSE) Author: Diccon_Yamanaka (Xara Group Ltd) Created: 30/4/99 Inputs: Distance = a length along the path Outputs: pPoint = the coordinate of the point that distance along the path pTangent = tangent at this point (can be NULL) UseCache - whether or not to use the cached path processor (don't unless a) you're sure it hasn't been deleted and b) you only want consecutive points). Returns: TRUE/FALSE for success/failure Purpose: Gets the coordinate of a point a certain distance along this path Calls the underlying Path class function This is identical to the version in ndbldpth.cpp except that this uses the cached version of path::Getpointatdistance ********************************************************************************************/ BOOL NodeBrushPath::GetPointAtDistance(MILLIPOINT Distance, DocCoord* pPoint, double* pTangent, BOOL UseCache) { ERROR2IF(pPoint == NULL,FALSE,"NULL pPoint param"); BOOL Found = FALSE; CPathPointInfo PointInfo; if (m_pCachedPointsAtDistance == NULL) { m_pCachedPointsAtDistance = new CMap; // if (m_pCachedPointsAtDistance != NULL) // m_pCachedPointsAtDistance->InitHashTable(1277); // Init hash table size to a suitably large prime number } if (m_pCachedPointsAtDistance != NULL) { Found = m_pCachedPointsAtDistance->Lookup(Distance,PointInfo); //if (Found) // TRACEUSER( "Diccon", _T("Point %d, %d found in cache\n"), PointInfo.m_Point.x, PointInfo.m_Point.y); } if (!Found) { // if we are drawing the brush then use the cached path processor, otherwise // use the normal one if (UseCache) { BOOL PointFound = FALSE; INT32 NumCoords; NumCoords = m_pProcessPath->GetCoordAndTangentWithCache( &PointInfo.m_Point, &PointInfo.m_Tangent, &PointFound, Distance ,&InkPath); if ((NumCoords != -1) && PointFound) { if (m_pCachedPointsAtDistance != NULL) m_pCachedPointsAtDistance->SetAt(Distance,PointInfo); Found = TRUE; } } else { if (InkPath.GetPointAtDistance(Distance,&PointInfo.m_Point,&PointInfo.m_Tangent)) { if (m_pCachedPointsAtDistance != NULL) m_pCachedPointsAtDistance->SetAt(Distance,PointInfo); // TRACEUSER( "Diccon", _T("Point %d, %d found from line\n"), PointInfo.m_Point.x, PointInfo.m_Point.y); Found = TRUE; } } } if (Found) { *pPoint = PointInfo.m_Point; if (pTangent) *pTangent = PointInfo.m_Tangent; } // if (Found == FALSE) // TRACEUSER( "Diccon", _T("Not found at distance %d\n"), Distance); return Found; } /******************************************************************************************** > void NodeBrushPath::ResetPathProcCache() Author: Diccon_Yamanaka (Xara Group Ltd) Created: 28/11/99 Inputs: - Purpose: To reset the cache used by the inkpath member, call this if you are going to alter the path in any way ********************************************************************************************/ void NodeBrushPath::ResetPathProcCache() { //InkPath.ResetCoordsProcessed(); } /******************************************************************************************** > BOOL NodeBrushPath::InitialisePathProcessor() Author: Diccon_Yamanaka (Xara Group Ltd) Created: 28/11/99 Inputs: - Purpose: To create a new path processor object SeeAlso: - ********************************************************************************************/ BOOL NodeBrushPath::InitialisePathProcessor() { if (m_pProcessPath != NULL) { delete m_pProcessPath; m_pProcessPath = NULL; } //m_pProcessPath = new ProcessPathDistance(64); //ERROR2IF(m_pProcessPath == NULL, FALSE, "Unable to allocate ProcessPathDistance object"); return TRUE; }