pbecomea.cpp

Go to the documentation of this file.
00001 // $Id: pbecomea.cpp 1361 2006-06-25 16:43:38Z 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 //
00099 // Implementation of PathBecomeA.
00100 //
00101 
00102 #include "camtypes.h"   // pre-compiled header.
00103 #include "pbecomea.h"   // make shapes stuff.
00104 
00105 #include "strkattr.h"   // AttrStrokeType use.
00106 #include "ppstroke.h"
00107 
00108 #include "nodepath.h"   // NodePath reference.
00109 #include "lineattr.h"   // for line width & colour attributes.
00110 #include "ndclpcnt.h"   // for ClipView path constants.
00111 #include "attrmap.h"
00112 
00113 DECLARE_SOURCE("$Revision: 1361 $");
00114 
00115 // dynamic class creation stuff.
00116 CC_IMPLEMENT_MEMDUMP(PathBecomeA, BecomeA)
00117 CC_IMPLEMENT_MEMDUMP(ContourBecomeA2, PathBecomeA)
00118 
00119 // Declare smart memory handling in Debug builds
00120 #define new CAM_DEBUG_NEW
00121 
00122 
00123 
00124 /********************************************************************************************
00125 
00126 >   PathBecomeA::PathBecomeA(   BecomeAReason baReason, CCRuntimeClass* pClass,
00127                                 UndoableOperation* pUndoOp, BOOL bSel, Path* pResultPath,
00128                                 enum OutlineRules OutlineRule = IGNORE_OUTLINES )
00129     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
00130     Created:    10 February 2000
00131     Inputs:     baReason    the reason for the call to this function.
00132                 pClass      the type of class required - ie a NodePath.
00133                 pUndoOp     ptr to the Op requesting the BecomeA.
00134                 bSel        whether to select the newly created node (unused in this class).
00135                 pResultPath points to a Path object in which to leave the results.
00136 
00137                 fRemoveOutlines     if set, then we strip the area obscured by any object
00138                                     outlines, from the resultant path.
00139 
00140     Outputs:    After a call to DoBecomeA with this parameter object, baReason set to
00141                 BECOMEA_PASSBACK and pClass set to NodePath, pResultPath should contain the 
00142                 outline(s) of whatever node was asked to DoBecomeA.
00143 
00144     Notes:      It is up to the caller to create, initialise and destroy the Path object 
00145                 pointed to by pResultPath. All we do is fill the path object with the
00146                 required information.
00147 
00148                 Outline rules - as an example, imagine processing two overlapping circles
00149                 with 20pt line width:
00150                 IGNORE_OUTLINES     the default; result - the path which would enclose
00151                                     both circles if their line widths were set to 0.
00152 
00153                 STRIP_OUTLINES      the path which would result if you drew the circles,
00154                                     then erased the areas covered by their thick line widths.
00155 
00156                 ADD_OUTLINES        the path which would result if you drew the circles,
00157                                     complete with thick line widths.
00158 
00159 ********************************************************************************************/
00160 PathBecomeA::PathBecomeA(   BecomeAReason baReason, CCRuntimeClass* pClass,
00161                             UndoableOperation* pUndoOp, BOOL bSel, Path* pResultPath,
00162                             enum OutlineRules OutlineRule )
00163                             : BecomeA(baReason, pClass, pUndoOp, bSel)
00164 {
00165     // initialise our pointer to the result-path.
00166     m_pResultPath = pResultPath;
00167 
00168     // initialise our outlines behaviour.
00169     m_OutlineRule = OutlineRule;
00170     if (m_OutlineRule == STRIP_OUTLINES)
00171         m_ClipPathRule = 4;
00172     else if (m_OutlineRule == ADD_OUTLINES)
00173         m_ClipPathRule = 7;
00174 }
00175 
00176 
00177 
00178 PathBecomeA::~PathBecomeA()
00179 {
00180     // empty our pointer to the result-path.
00181     m_pResultPath = NULL;
00182 }
00183 
00184 
00185 
00186 /********************************************************************************************
00187 
00188 >   virtual BOOL PathBecomeA::Passback( NodeRenderableInk* pNewNode,
00189                                         NodeRenderableInk*& pCreatedByNode,
00190                                         CCAttrMap* pAttrMap = NULL)
00191     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
00192     Created:    10 February 2000
00193     Inputs:     pNewNode        points to a new NodeRenderableInk created as a result of the 
00194                                 BecomeA operation.
00195                 pCreatedByNode  the node which called us.
00196                 pAttrMap        an attribute map - useful for stroking paths...
00197 
00198     Returns:    TRUE if successful, FALSE otherwise.
00199 
00200     Purpose:    Called by DoBecomeA when a node is asked to convert itself to another type of 
00201                 node. The passed-in new node is expected to be a NodePath. We extract its 
00202                 actual Path, and add it to the path referenced by a pointer we were given at 
00203                 construction.
00204 
00205     Notes:      The possible node tree pointed to by pNewNode, together with pAttrMap, must 
00206                 both be destroyed by this function - no-one else is going to do it.
00207 
00208     Errors:     ERROR2 with FALSE if pNewNode is NULL or is not a path.
00209     See also:   BecomeA::PassBack()
00210 
00211 ********************************************************************************************/
00212 BOOL PathBecomeA::PassBack( NodeRenderableInk* pNewNode,
00213                             NodeRenderableInk* pCreatedByNode,
00214                             CCAttrMap* pAttrMap )
00215 {
00216     // validate inputs.
00217     ERROR2IF(   pNewNode == NULL || !pNewNode->IsNodePath(),
00218                 FALSE,
00219                 "PathBecomeA::PassBack; Passed back node was NULL, or not a path" );
00220 
00221     ERROR2IF(   m_pResultPath == NULL, FALSE,
00222                 "PathBecomeA::PassBack; NULL result path!"  );
00223 
00224     BOOL fDeleteAttributes  = TRUE;
00225     BOOL fDeleteFillPath    = FALSE;
00226 
00227     const INT32 Flatness = NodeClipViewController::EstimatePathFlatness();
00228 
00229     // try to get an attribute map for converting the outline to shapes.
00230     if (pAttrMap == NULL)
00231     {
00232         fDeleteAttributes = FALSE;
00233         pAttrMap = CCAttrMap::MakeAppliedAttrMap(pCreatedByNode);
00234     }
00235 
00236     NodePath* pNewNodePath = (NodePath*)pNewNode;
00237 
00238     Path* pFillPath = &( pNewNodePath->InkPath );
00239     Path* pLinePath = NULL;
00240 
00241     // ok, first try to get the node's outline as a closed path.
00242     // we obviously won't get anything unless the outline's non-transparent.
00243     pLinePath = ExtractOutlineAsPath(pNewNodePath, pAttrMap);
00244 
00245     // providing the fill-path is filled, we'll use it as is.
00246     if (pFillPath->IsFilled)
00247     {
00248         if (pFillPath->GetNumCoords() < 3)
00249             pFillPath->ClearPath();
00250     }
00251 
00252     // if the fill-path is open, then we'll use the line path instead.
00253     else
00254     {
00255         fDeleteFillPath = TRUE;
00256         pFillPath = pLinePath;
00257         pLinePath = NULL;
00258     }
00259 
00260     // provided it exists, add the fill-path to the results path.
00261     if (pFillPath != NULL && pFillPath->GetNumCoords() > 0)
00262     {
00263         // if our results path is empty, just plonk the fill path in it.
00264         if (m_pResultPath->GetNumCoords() == 0)
00265             m_pResultPath->CloneFrom(*pFillPath);
00266 
00267         // otherwise, add our fill path to the current results path.
00268         // there's a slight optimisation here - if the bounds of the two paths don't overlap,
00269         // then the path union can be done simply by merging them together.
00270         else
00271         {
00272             BOOL fBoundsOverlap = FALSE;
00273             DocRect drResultPath(0, 0, 0, 0);
00274             DocRect drFillPath(0, 0, 0, 0);
00275             if (m_pResultPath->GetTrueBoundingRect(&drResultPath))
00276                 if (pFillPath->GetTrueBoundingRect(&drFillPath))
00277                     if (drFillPath.IsIntersectedWith(drResultPath))
00278                         fBoundsOverlap = TRUE;
00279 
00280             if (!fBoundsOverlap)
00281                 m_pResultPath->MergeTwoPaths(*pFillPath);
00282 
00283             else
00284             {
00285                 m_pResultPath->ClipPathToPath(  *pFillPath, m_pResultPath, 7,
00286                                                 NodeClipViewController::CLIPVIEW_TOLERANCE,
00287                                                 Flatness,
00288                                                 Flatness );
00289 
00290                 // there is a bug here somewhere.  If pCreatedByNode just happens to have a stroke
00291                 // applied to it, then the above call to ClipPathToPath seems to invert the path!
00292                 // I'm not sure what to do about this, so for now it going to have to be left ....
00293                 // NOTE:  to observe the bug, group two (overlapping) quickshapes, apply a stroke to
00294                 // the group and slice with a line.
00295             }
00296         }
00297     }
00298 
00299     // if we're not ignoring outlines and we have a valid outline,
00300     // then throw it into the soup.
00301     if (m_OutlineRule != IGNORE_OUTLINES)
00302     {
00303         if (pLinePath != NULL)
00304         {
00305             m_pResultPath->ClipPathToPath(  *pLinePath, m_pResultPath, m_ClipPathRule | 0x10,
00306                                             NodeClipViewController::CLIPVIEW_TOLERANCE,
00307                                             Flatness,
00308                                             Flatness );
00309         }
00310 
00311         // a side-effect of the ClipPathToPath call above is that it ensures the path is tidy.
00312         // this ClipPathToPath call does the same thing.
00313         else
00314             m_pResultPath->ClipPathToPath(*m_pResultPath, m_pResultPath, 3, 20, 75, 75);
00315     }
00316 
00317     // PathBecomeA tries to return closed paths, so ensure our results path is marked so.
00318     if (!m_pResultPath->IsFilled)
00319         m_pResultPath->IsFilled = TRUE;
00320 
00321     // clear away all our temporary info.
00322     // no NULL assignments required, as these vars are all about to go out of scope.
00323     if (pLinePath != NULL)
00324         delete pLinePath;
00325 
00326     if (fDeleteFillPath && pFillPath != NULL)
00327         delete pFillPath;
00328 
00329     if (pAttrMap != NULL)
00330     {
00331         if (fDeleteAttributes)
00332             pAttrMap->DeleteAttributes();
00333 
00334         delete pAttrMap;
00335     }
00336 
00337     pNewNode->CascadeDelete();
00338     delete pNewNode;
00339 
00340     return TRUE;
00341 }
00342 
00343 
00344 
00345 /********************************************************************************************
00346 
00347 >   Path* PathBecomeA::ExtractOutlineAsPath(NodePath* pSrcNodePath, CCAttrMap* pAttrMap)
00348 
00349     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
00350     Created:    18/11/2000
00351     Inputs:     pSrcNodePath    a NodePath whose outline we're going to extract.
00352                 pAttrMap        the attribute map from which we'll get line attributes,
00353                                 eg width, cap style, join style etc.
00354     Returns:    A ptr to a path if successful,
00355                 NULL otherwise.
00356 
00357     Purpose:    Given a NodePath and an attribute map, construct the Path which delineates
00358                 the NodePath's outline. If the line width of the path is 0pt, you'll get
00359                 a NULL ptr back.
00360 
00361     Notes:      This method returns a Path allocated on the heap - it's *your* responsibility
00362                 to delete it!
00363 
00364                 Either input can be NULL, in which case you'll get a NULL ptr back.
00365 
00366                 This method should really just take a pure Path* for flexibility,
00367                 however we make use of MakeNodePathFromAttributes(), which is a NodePath
00368                 method. I'm fed up of rewriting other people's code at the moment and
00369                 I don't want to potentially destabilise the code base before a release.
00370                 If you want to rewrite MakeNodePath... and this method to take a pure Path*,
00371                 be my guest :o)
00372 
00373 ********************************************************************************************/
00374 Path* PathBecomeA::ExtractOutlineAsPath(NodePath* pSrcNodePath, CCAttrMap* pAttrMap)
00375 {
00376     // we can accept NULL inputs - we just don't do any processing for them.
00377     if (pAttrMap == NULL || pSrcNodePath == NULL)
00378         return NULL;
00379 
00380     const INT32 Flatness = NodeClipViewController::EstimatePathFlatness();
00381 
00382     Path* pFillPath     = &( pSrcNodePath->InkPath );
00383     Path* pStrokePath   = NULL;
00384 
00385     // we only need to generate an outline path if the path has non-transparent line colour.
00386     BOOL bHaveAnOutline = FALSE;
00387     AttrStrokeColour* pAttrStrokeColour = NULL;
00388     pAttrMap->Lookup( CC_RUNTIME_CLASS(AttrStrokeColour), (void*&)pAttrStrokeColour );
00389     if (pAttrStrokeColour != NULL)
00390     {
00391         DocColour* pLineColour = pAttrStrokeColour->GetStartColour();
00392         if (pLineColour != NULL && !pLineColour->IsTransparent())
00393         {
00394             bHaveAnOutline = TRUE;
00395         }
00396     }
00397 
00398     // ok, if we don't have an outline, then go home now.
00399     if (!bHaveAnOutline)
00400         return NULL;
00401 
00402     // if the line is stroked, then use the stroke's path-processor to give us the outline.
00403     AttrStrokeType* pAttrStrokeType = NULL;
00404     pAttrMap->Lookup( CC_RUNTIME_CLASS(AttrStrokeType), (void*&)pAttrStrokeType );
00405     if (pAttrStrokeType != NULL && pAttrStrokeType->HasPathProcessor())
00406     {
00407         PathProcessorStroke* pPPS = pAttrStrokeType->GetPathProcessor();
00408         if (pPPS != NULL)
00409         {
00410             pStrokePath = pPPS->GetProcessedPath(pFillPath, pAttrMap);
00411             pStrokePath->ClipPathToPath(*pStrokePath, pStrokePath, 3 | 0x10, 20, 75, 75);
00412         }
00413     }
00414 
00415     // if it's a simple line, then use DavidMc's MakeNodePath... method.
00416     else
00417     {
00418         NodePath* pNodeOutline = NULL;
00419         pNodeOutline = pSrcNodePath->MakeNodePathFromAttributes(Flatness,
00420                                                                 pAttrMap,
00421                                                                 TRUE);
00422         if (pNodeOutline != NULL)
00423         {
00424             pStrokePath = pNodeOutline->GetPathCopy();
00425             delete pNodeOutline;
00426             pNodeOutline = NULL;
00427         }
00428     }
00429 
00430     return pStrokePath;
00431 }
00432 
00433 
00434 
00435 //-------------------------------------------------------------------------------------------
00436 //-------------------------------------------------------------------------------------------
00437 //-------------------------------------------------------------------------------------------
00438 //-------------------------------------------------------------------------------------------
00439 
00440 
00441 
00442 /********************************************************************************************
00443 
00444 >   ContourBecomeA2::ContourBecomeA2(   UndoableOperation* pUndoOp,
00445                                         MILLIPOINT Width,
00446                                         Path* pResultPath   )
00447     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
00448     Created:    21/11/2000
00449     Inputs:     pUndoOp         pointer to an Op, if you have one.
00450                 Width           how far out you want me to contour, in millipoints.
00451                 pResultPath     where you want me to plonk the contour - must point to
00452                                 an initialised path which you don't mind me emptying.
00453 
00454     Purpose:    Constructor for a new ContourBecomeA, to do your contouring dirty work :o)
00455 
00456 ********************************************************************************************/
00457 ContourBecomeA2::ContourBecomeA2(   UndoableOperation* pUndoOp,
00458                                     MILLIPOINT Width,
00459                                     Path* pResultPath   )
00460                                     : PathBecomeA(  BECOMEA_PASSBACK,
00461                                                     CC_RUNTIME_CLASS(NodePath),
00462                                                     pUndoOp,
00463                                                     FALSE,
00464                                                     pResultPath,
00465                                                     ADD_OUTLINES )
00466 {
00467     m_Width = Width;
00468     SetDoSilhouette(TRUE);
00469     SetDoShadowSilhouettes(TRUE);
00470 }
00471 
00472 
00473 
00474 /********************************************************************************************
00475 
00476 >   BOOL ContourBecomeA2::PassBack( NodeRenderableInk* pNewNode,
00477                                     NodeRenderableInk* pCreatedByNode,
00478                                     CCAttrMap* pAttrMap )
00479     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
00480     Created:    21/11/2000
00481 
00482     Inputs:     pNewNode        ptr to the NodePath which you're passing in to me
00483                                 (don't expect it back).
00484                 pCreatedByNode  ptr to the node which created the NodePath - useful to me
00485                                 if you don't supply an attr-map.
00486                 pAttrMap        ptr to an attr-map for me to get line attributes out of
00487                                 when I stroke the path. Not compulsory
00488 
00489     Outputs:    pResultPath will contain the result of doing a contour outwards from the
00490                 DoBecomeA-ing objects.
00491 
00492     Returns:    TRUE if successful, FALSE if not.
00493 
00494     Purpose:    PassBack function fer lettin' me do ma contour thang.
00495 
00496 ********************************************************************************************/
00497 BOOL ContourBecomeA2::PassBack( NodeRenderableInk* pNewNode,
00498                                 NodeRenderableInk* pCreatedByNode,
00499                                 CCAttrMap* pAttrMap )
00500 {
00501     Path* pContourPath          = NULL;
00502     Path* pSummedContourPath    = m_pResultPath;
00503 
00504     m_pResultPath = new Path;
00505     BOOL    ok = (m_pResultPath != NULL);
00506     if (ok) ok = m_pResultPath->Initialise();
00507     if (ok)
00508     {
00509         PathBecomeA::PassBack(pNewNode, pCreatedByNode, pAttrMap);
00510         ok = (m_pResultPath->GetNumCoords() != 0);
00511     }
00512     if (ok)
00513     {
00514         pContourPath = new Path;
00515         ok = (pContourPath != NULL);
00516     }
00517     if (ok) ok = pContourPath->Initialise();
00518     if (ok)
00519     {
00520         TRACEUSER( "Karim", _T("Node at 0x%x; ResultPath - %d coords.\n"),
00521                             pCreatedByNode,
00522                             m_pResultPath->GetNumCoords());
00523 
00524         m_pResultPath->InitializeContourValues(2 * m_Width);
00525         m_pResultPath->GetContourForStep(pContourPath);
00526 
00527         delete m_pResultPath;
00528         m_pResultPath = pSummedContourPath;
00529 
00530         if (pContourPath->GetNumCoords() != 0)
00531             pContourPath->ClipPathToPath(*m_pResultPath, m_pResultPath, 7, 20, 75, 75);
00532 
00533         if (!m_pResultPath->IsFilled)
00534             m_pResultPath->IsFilled = TRUE;
00535 
00536         delete pContourPath;
00537     }
00538 
00539     return ok;
00540 }

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