#include <combshps.h>
Inheritance diagram for OpCombineShapes:

Public Member Functions | |
| OpCombineShapes () | |
| Default constructor. | |
| ~OpCombineShapes () | |
| Default destructor - does nothing. | |
| virtual void | Do (OpDescriptor *) |
| This is it! The routine that gets all the hard work underway. | |
| virtual void | GetOpName (String_256 *) |
| The GetOpName fn is overridden so that we return back a description appropriate to the type of attribute that the operation applies. | |
Static Public Member Functions | |
| static BOOL | Init () |
| Declares a preference that allows you to clear memory in delete(). | |
| static OpState | GetState (String_256 *, OpDescriptor *) |
| Gives the op an oppertunity to say whether the op is executable or not. | |
Protected Attributes | |
| CombineReason | Reason |
Private Member Functions | |
| BOOL | ConvertToShapes (Range *pRange, BOOL bCombineEffectBitmaps) |
| This subtracts all the shapes in all the lists from all the lines in all the lists This subtracts all the shapes in all the lists from pLine This subtracts all the shapes in pSelObjPathList from pLine This generates the data structure that holds all the paths generated by the selected objects. NOTE! Pointers to paths in the tree are stored in the lists (unlike CreateSelObjPathLists). | |
| BOOL | CreateSelObjPathLists (BOOL bCombineEffectBitmaps) |
| This generates the data structure that holds all the paths generated by the selected objects. | |
| BOOL | CreateSelObjPathList (Node *pNode, SelObjPathList *pSelObjPathList, BOOL IsFirstNode=TRUE, BOOL bCombineEffectBitmaps=TRUE, BecomeAReason reason=BECOMEA_PASSBACK) |
| This generates the data structure that holds all the paths generated by a given selected object. | |
| BOOL | DoAddShapes () |
| This adds all the paths together to form a combined silhouette path of the selection. | |
| BOOL | AddPathsFromList (Path *pPath, SelObjPathList *pSelObjPathList) |
| This adds all the paths in the list together to form a combined silhouette path of the selection. | |
| BOOL | AddPaths (Path *pPath1, Path *pPath2) |
| This adds the two paths together using ClipPathToPath, storing the result in pPath1. | |
| BOOL | AddOrMergePaths (Path *pPath1, Path *pPath2) |
| Helper function for DoAddShapes and AddPathsFromList. | |
| BOOL | DoCombineShapes (ClipStyle Style, BOOL bCombineEffectBitmaps) |
| Firstly, this adds all the paths together in the last list to form the clip path. Then all the other paths in the other lists are combined with the clip path, using the method specified in 'Flags'. | |
| BOOL | CombinePathsFromList (ClipStyle Style, Path *pClipPath, Path *pStrokedClipPath, SelObjPathList *pSelObjPathList, BOOL bCombineEffectBitmaps=TRUE) |
| This combines pClipPath with all the paths in pSelObjPathList. | |
| BOOL | CombinePaths (ClipStyle Style, Path *pClipPath, Path *pStrokedClipPath, Path *pSrcPath, Path *pDestPath) |
| This combines pClipPath from pSrcPath using ClipPathToPath, storing the result in pDestPath. | |
| BOOL | DoHideListedNodes (BOOL bCombineEffectBitmaps) |
| This hides all the nodes that were selected when the op was invoked. | |
| BOOL | DoSelectResultNodes (BOOL bCombineEffectBitmaps) |
| This selects all the nodes in the results list. | |
| BOOL | ApplyAttributes (NodeRenderableInk *pSrcNode, NodeRenderableInk *pDestNode, CCAttrMap *pAttrMap, SelObjPathListItem *pListItem=NULL) |
| This applies attrs pDestNode. If pAttrMap == NULL, the attrs applied to pSrcNode are applied to pDestNode, else the attrs in pAttrMap are applied. | |
| BOOL | ApplyEffects (SelObjPathListItem *pListItem, NodeRenderableInk *pDestNode, NodeRenderableInk *pParentEffect) |
| To delete the extra attributes we allocated in AdjustAttributesForStroke This applies attrs pDestNode. If pAttrMap == NULL, the attrs applied to pSrcNode are applied to pDestNode, else the attrs in pAttrMap are applied. | |
| BOOL | StrokePathToPath (Path *pPath, Path *pDest) |
| This picks out a subpath from Src and places it into pDest Strokes pPath, and places result in pDest. | |
| BOOL | ConvertClipLineToShape (Path *pClipPath, Path *pSrcPath, Path *pDestPath) |
| Only call this if pClipPath is a line. | |
| DocRect | GetBoundingRect (Path *pPath) |
| This gets the exact pure path bounds, using GDraw_CalcStrokeBBox. | |
| BOOL | DoInsertNewNode (NodeRenderableBounded *pNewNode) |
| High-level interface to UndoableOperation::DoInsertNode(). | |
| UINT32 | AdjustAttributesForStroke (CCAttrMap *pAttrMap, SelObjPathListItem *pListItem=NULL) |
| If we are doing combine shapes on a stroked shape then we need to make the following changes: 1) Do not keep the AttrStrokeType and VariableWidth around, this is because their effects have been achieved via the DoBecomeA so if we keep them then effectively we are stroking our final output twice. 2) Set line width to zero. Once again the line width effect has been extracted from the DoBecomeA 3) Use the current stroke colour for the new fill colour. 4) Ditch the stroke colour? | |
| BOOL | BeginSlowJob () |
| Wrapper around BeginSlowJob() that sets up the hour glass counter correctly. | |
| SelObjPathList * | GetFirstList () |
| SelObjPathList * | GetLastList () |
| SelObjPathList * | GetNextList (SelObjPathList *pItem) |
| ListRange * | CopyRange (Range *pRange) |
| Copy the specified range of nodes. | |
Private Attributes | |
| List | ListOfSelObjPathLists |
| ListRange * | pListOfResults |
| DocRect | OriginalBoundingRect |
| SelRange * | pSelRange |
| INT32 | NumPaths |
| INT32 | JobCount |
| INT32 | NodeInsertCount |
| Node * | pContextNode |
| AttachNodeDirection | AttachDir |
Definition at line 232 of file combshps.h.
|
|
Default constructor.
Definition at line 167 of file combshps.cpp. 00168 { 00169 Reason = COMBINE_NONE; 00170 pSelRange = NULL; 00171 NumPaths = 0; 00172 JobCount = 0; 00173 00174 pContextNode = NULL; 00175 pListOfResults = NULL; 00176 }
|
|
|
Default destructor - does nothing.
Definition at line 193 of file combshps.cpp. 00194 { 00195 ListOfSelObjPathLists.DeleteAll(); 00196 if (pListOfResults) 00197 { 00198 delete pListOfResults; 00199 pListOfResults = NULL; 00200 }; 00201 }
|
|
||||||||||||
|
Helper function for DoAddShapes and AddPathsFromList.
Definition at line 749 of file combshps.cpp. 00750 { 00751 BOOL ok = TRUE; 00752 // if num coords == 0, the path is effectively empty, so just copy this node path's path 00753 if (pPath1->GetNumCoords() == 0) 00754 ok = pPath1->MergeTwoPaths(*pPath2); 00755 else 00756 { 00757 // Otherwise actually 'add' the paths together, using ClipPathToPath 00758 ok = AddPaths(pPath1,pPath2); 00759 00760 // If this fails, we can just merge the two paths together as this achieves the desired 00761 // silhouette effect 00762 if (!ok) ok = pPath1->MergeTwoPaths(*pPath2); 00763 00764 } 00765 return(ok); 00766 }
|
|
||||||||||||
|
This adds the two paths together using ClipPathToPath, storing the result in pPath1.
Definition at line 785 of file combshps.cpp. 00786 { 00787 ERROR2IF(pPath1 == NULL,FALSE,"pPath1 == NULL"); 00788 ERROR2IF(pPath2 == NULL,FALSE,"pPath2 == NULL"); 00789 00790 // check for a zero-bounding box path 00791 DocRect dr = pPath2->GetBoundingRect(); 00792 00793 if (dr.Width() <= 1 && dr.Height() <= 1) 00794 { 00795 ERROR3("We have a zero bounding rect path"); 00796 return FALSE; 00797 } 00798 00799 Path StrokedPath2; 00800 if (!StrokedPath2.Initialise()) return FALSE; 00801 00802 // is path 2 a line? 00803 if (pPath2->GetPathType() == PATHTYPE_LINE) 00804 { 00805 if (!StrokePathToPath(pPath2,&StrokedPath2)) 00806 return FALSE; 00807 } 00808 00809 INT32 len = CombinePaths(CLIP_STYLE_ADD,pPath2,&StrokedPath2,pPath1,pPath1); 00810 00811 return (len > 0); 00812 }
|
|
||||||||||||
|
This adds all the paths in the list together to form a combined silhouette path of the selection.
Definition at line 671 of file combshps.cpp. 00672 { 00673 // Check our input params 00674 ERROR3IF(pPath == NULL,"pPath == NULL"); 00675 ERROR3IF(pSelObjPathList == NULL,"pSelObjPathList== NULL"); 00676 if (pPath == NULL || pSelObjPathList == NULL) return FALSE; 00677 00678 NodePath* pTempPath = new NodePath; 00679 if (pTempPath == NULL) return FALSE; 00680 if (!pTempPath->SetUpPath()) return FALSE; 00681 00682 // Get the first path in this list 00683 SelObjPathListItem* pSelObjPathListItem = pSelObjPathList->GetFirstItem(); 00684 00685 BOOL ok = TRUE; 00686 00687 while (ok && pSelObjPathListItem != NULL) 00688 { 00689 // Get a pointer to the actual node path in this list item 00690 Path* pSrcPath = pSelObjPathListItem->GetPath(); 00691 00692 if (pSrcPath != NULL) 00693 { 00694 // Add this path into the TempPath 00695 ok = AddOrMergePaths(&(pTempPath->InkPath), pSrcPath); 00696 00697 // If the TempPath is now too large 00698 if (ok && pTempPath->InkPath.GetNumCoords() > AddPathGranularity) 00699 { 00700 // Combine the TempPath with the output path 00701 ok = AddOrMergePaths(pPath, &(pTempPath->InkPath)); 00702 // And clear the TempPath 00703 if (ok) ok = pTempPath->InkPath.ClearPath(FALSE); 00704 } 00705 if (ok) pSelObjPathList->SetProducedPaths(TRUE); 00706 } 00707 else 00708 { 00709 // What? No Src path? Surely not! 00710 ERROR3("pSrcPath == NULL"); 00711 ok = FALSE; 00712 } 00713 00714 if (ok) 00715 ok = ::ContinueSlowJob(++JobCount); 00716 00717 // Get the next item in the selected object path list. 00718 pSelObjPathListItem = pSelObjPathList->GetNextItem(pSelObjPathListItem); 00719 } 00720 00721 // If the TempPath has anything in 00722 if (ok && pTempPath->InkPath.GetNumCoords() > 0) 00723 { 00724 // Combine the TempPath with the output path 00725 ok = AddOrMergePaths(pPath, &(pTempPath->InkPath)); 00726 } 00727 00728 delete pTempPath; 00729 00730 return (ok); 00731 }
|
|
||||||||||||
|
If we are doing combine shapes on a stroked shape then we need to make the following changes: 1) Do not keep the AttrStrokeType and VariableWidth around, this is because their effects have been achieved via the DoBecomeA so if we keep them then effectively we are stroking our final output twice. 2) Set line width to zero. Once again the line width effect has been extracted from the DoBecomeA 3) Use the current stroke colour for the new fill colour. 4) Ditch the stroke colour?
Definition at line 2135 of file combshps.cpp. 02136 { 02137 if (pAttrMap == NULL) 02138 return 0; 02139 02140 // first see if we have an active stroke, if not we can just quit already 02141 AttrStrokeType* pStroke = NULL; 02142 pAttrMap->Lookup(CC_RUNTIME_CLASS(AttrStrokeType), (void*&)pStroke); 02143 02144 if (pStroke == NULL || !pStroke->HasPathProcessor()) 02145 return 0; 02146 02147 AttrVariableWidth* pVarWidth = NULL; 02148 pAttrMap->Lookup(CC_RUNTIME_CLASS(AttrVariableWidth), (void*&)pVarWidth); 02149 02150 // CGS: we should only really continue IF we have an active value function! Otherwise, we seem to run 02151 // into problems when we have give new objects most recent attributes turned on .... 02152 if ((pVarWidth == NULL) || !pVarWidth->HasActiveValueFunction ()) 02153 return (0); 02154 02155 // right so we want to set the line width to zero 02156 AttrLineWidth* pLineWidth = new AttrLineWidth; 02157 if (pLineWidth != NULL) 02158 { 02159 pAttrMap->RemoveAttribute(CC_RUNTIME_CLASS(AttrLineWidth)); 02160 pLineWidth->Value.LineWidth = 0; 02161 pAttrMap->SetAt(CC_RUNTIME_CLASS(AttrLineWidth), (void*)pLineWidth); 02162 } 02163 02164 // now get the stroke colour and use it to make a fill colour 02165 AttrStrokeColour * pColour = NULL; 02166 02167 // look up the stroke colour attribute 02168 pAttrMap->Lookup(CC_RUNTIME_CLASS(AttrStrokeColour), 02169 (void *&)pColour); 02170 02171 02172 // make a new flat fill attribute and apply this to the node 02173 if (pColour) 02174 { 02175 if (!pListItem || pListItem->GetStrokeCreatedPassbackPath ()) 02176 { 02177 StrokeColourAttribute * pAttrVal = (StrokeColourAttribute *)pColour->GetAttributeValue(); 02178 02179 if (pAttrVal) 02180 { 02181 AttrFlatColourFill* pFill = new AttrFlatColourFill; 02182 02183 if (pFill) 02184 { 02185 DocColour Col = pAttrVal->Colour; 02186 pFill->SetStartColour(&Col); 02187 02188 // set back in the map 02189 pAttrMap->RemoveAttribute(CC_RUNTIME_CLASS(AttrFillGeometry)); 02190 pAttrMap->SetAt(CC_RUNTIME_CLASS(AttrFillGeometry), (void*)pFill); 02191 } 02192 else 02193 return 2; 02194 } 02195 } 02196 // now make a new stroke colour and set it transparent 02197 AttrStrokeColour* pNewStrokeCol = new AttrStrokeColour; 02198 if (pNewStrokeCol) 02199 { 02200 pNewStrokeCol->Value.Colour = DocColour(COLOUR_NONE); 02201 pAttrMap->RemoveAttribute(CC_RUNTIME_CLASS(AttrStrokeColour)); 02202 pAttrMap->SetAt(CC_RUNTIME_CLASS(AttrStrokeColour), (void*)pNewStrokeCol); 02203 } 02204 } 02205 02206 // now remove the stroke and var width attributes, and any brushes whilst we're here 02207 pAttrMap->RemoveAttribute(CC_RUNTIME_CLASS(AttrVariableWidth)); 02208 pAttrMap->RemoveAttribute(CC_RUNTIME_CLASS(AttrStrokeType)); 02209 pAttrMap->RemoveAttribute(CC_RUNTIME_CLASS(AttrBrushType)); 02210 02211 return 1; 02212 }
|
|
||||||||||||||||||||
|
This applies attrs pDestNode. If pAttrMap == NULL, the attrs applied to pSrcNode are applied to pDestNode, else the attrs in pAttrMap are applied.
Definition at line 2063 of file combshps.cpp. 02064 { 02065 ERROR3IF(pSrcNode == NULL,"pSrcNode == NULL"); 02066 ERROR3IF(pDestNode == NULL,"pDestNode == NULL"); 02067 if (pSrcNode == NULL || pDestNode == NULL) return FALSE; 02068 02069 BOOL ok = TRUE; // Set to TRUE if we successfully apply attrs to pDestNode 02070 BOOL DeleteAttrs = FALSE; // TRUE if we need to delete attr map before returning 02071 02072 02073 if (pAttrMap == NULL) 02074 { 02075 // Find the currently applied attributes and make a local copy of the map (like most 02076 // passback functions do) 02077 CCAttrMap AppliedMap(30); 02078 ok = pSrcNode->FindAppliedAttributes(&AppliedMap); 02079 pAttrMap = AppliedMap.Copy(); 02080 DeleteAttrs = TRUE; 02081 } 02082 02083 // if we have a stroked object we need to do some attribute juggling 02084 if (AdjustAttributesForStroke(pAttrMap, pListItem) == 2) 02085 return FALSE; 02086 02087 // If all's OK, apply attrs to pDestNode 02088 ok = pDestNode->ApplyAttributes(pAttrMap,TRUE); 02089 02090 // Delete the copied attr map if we have to 02091 if (DeleteAttrs) 02092 { 02093 pAttrMap->DeleteAttributes(); 02094 delete pAttrMap; 02095 } 02096 02097 return ok; 02098 }
|
|
||||||||||||||||
|
To delete the extra attributes we allocated in AdjustAttributesForStroke This applies attrs pDestNode. If pAttrMap == NULL, the attrs applied to pSrcNode are applied to pDestNode, else the attrs in pAttrMap are applied.
Definition at line 2297 of file combshps.cpp. 02298 { 02299 BOOL ok = TRUE; 02300 PORTNOTE("other", "Removed OpCombineShapes::ApplyEffects"); 02301 #ifndef EXCLUDE_FROM_XARALX 02302 02303 ERROR3IF(pListItem == NULL, "pListItem == NULL"); 02304 ERROR3IF(pDestNode == NULL, "pDestNode == NULL"); 02305 02306 NodeRenderableInk* pSrcNode = pListItem->GetCreatedByNode(); 02307 ERROR3IF(pSrcNode == NULL, "pSrcNode == NULL"); 02308 02309 // Get the effect stack for the object which produced this path (pSrcNode) 02310 // If the source node had effects applied to it 02311 // And that stack is different than the stack above the context node 02312 // Then we must copy the effect stack onto the destination node 02313 ListRange* pStack = pListItem->GetEffectStack(); 02314 Node* pEffect = NULL; 02315 if (pStack) 02316 pEffect = pStack->FindFirst(); 02317 if (pEffect) 02318 { 02319 if (pParentEffect==NULL || pParentEffect!=pEffect) 02320 { 02321 // We need to copy the effect stack onto this object 02322 OpLiveEffect::DoCopyEffectsStack(this, pDestNode, pStack, GetWorkingDoc(), GetWorkingDoc()); 02323 } 02324 } 02325 #endif 02326 return ok; 02327 }
|
|
|
Wrapper around BeginSlowJob() that sets up the hour glass counter correctly.
Definition at line 382 of file combshps.cpp. 00383 { 00384 NumPaths = 0; 00385 JobCount = 0; 00386 SelObjPathList* pList = GetFirstList(); 00387 while (pList != NULL) 00388 { 00389 NumPaths += pList->GetCount(); 00390 pList = GetNextList(pList); 00391 } 00392 00393 INT32 SlowJobCount = NumPaths; 00394 if (Reason == COMBINE_SLICE) 00395 SlowJobCount *= 2; 00396 String_64 Str(_R(IDS_COMBINE_SLOWJOB)); 00397 return (::BeginSlowJob(SlowJobCount,FALSE,&Str)); 00398 }
|
|
||||||||||||||||||||||||
|
This combines pClipPath from pSrcPath using ClipPathToPath, storing the result in pDestPath.
Definition at line 1136 of file combshps.cpp. 01137 { 01138 // Check those entry params 01139 ERROR2IF(pClipPath == NULL,FALSE,"pClipPath == NULL"); 01140 ERROR2IF(pStrokedClipPath == NULL,FALSE,"pStrokedClipPath == NULL"); 01141 ERROR2IF(pSrcPath == NULL,FALSE,"pSrcPath == NULL"); 01142 ERROR2IF(pDestPath == NULL,FALSE,"pDestPath == NULL"); 01143 01144 UINT32 Flags = 0; // Flags passed to ClipPathToPath() 01145 BOOL Clip = TRUE; // If this is TRUE, ClipPathToPath() is called at the end of this func 01146 INT32 len = -1; // This is the length of the path produced by ClipPathToPath 01147 01148 BOOL SrcIsLine = (pSrcPath->GetPathType() == PATHTYPE_LINE); // TRUE if src path is a line 01149 BOOL ClipIsLine = (pClipPath->GetPathType() == PATHTYPE_LINE); // TRUE if clip path is a line 01150 01151 Path DestPath; // Used when using a line to slice the source path up 01152 01153 // If the clip path is a line and the op is slice, try and make a closed path using pClipPath 01154 // and the bounding rect of pSrcPath 01155 if (ClipIsLine && Reason == COMBINE_SLICE) 01156 { 01157 if (DestPath.Initialise() && ConvertClipLineToShape(pClipPath,pSrcPath,&DestPath)) 01158 { 01159 // If successfully created a closed path, then pretend func was entered with the new path 01160 // by pointing pClipPath to it. Also the clip path is no longer a line 01161 pClipPath = &DestPath; 01162 ClipIsLine = FALSE; 01163 } 01164 } 01165 01166 switch (Style) 01167 { 01168 case CLIP_STYLE_SUBTRACT: 01169 Flags = 1; // 1 is Source AND NOT Clip 01170 if (SrcIsLine) Flags |= CLIPPING_IS_STROKED; // If source is a line, set the stroked flag 01171 01172 if (ClipIsLine) 01173 { 01174 // If slicing with a line, don't bother doing the subtraction stage 01175 if (Reason == COMBINE_SLICE) 01176 Clip = FALSE; 01177 else 01178 // Otherwise subtract with a stroked version of the line. 01179 // If the user's mad enough to try it, then we'd better try our best 01180 { pClipPath = pStrokedClipPath; Flags |= CLIPPING_CLIP_WINDING; } 01181 } 01182 break; 01183 01184 case CLIP_STYLE_INTERSECT: 01185 // If src is a line, Flags = 0 | stroked flag, else Flags = Source AND Clip 01186 if (SrcIsLine) Flags = CLIPPING_IS_STROKED; else Flags = 2; 01187 if (ClipIsLine) 01188 { 01189 // If slicing with a line, don't bother doing the intersection stage 01190 if (Reason == COMBINE_SLICE) 01191 Clip = FALSE; 01192 else 01193 // Otherwise intersect with a stroked version of the line. 01194 // If the user's mad enough to try it, then we'd better try our best 01195 { pClipPath = pStrokedClipPath; Flags |= CLIPPING_CLIP_WINDING; } 01196 } 01197 break; 01198 01199 case CLIP_STYLE_ADD: 01200 Flags = 7; // 7 is Source OR Clip 01201 // convert lines into paths by stroking them 01202 // Also we must use a Non-zero winding rule to avoid cross segment lines taking effect 01203 if (SrcIsLine) { StrokePathToPath(pSrcPath,pSrcPath); Flags |= CLIPPING_SOURCE_WINDING; } 01204 if (ClipIsLine) { pClipPath = pStrokedClipPath; Flags |= CLIPPING_CLIP_WINDING; } 01205 break; 01206 } 01207 01208 if (Clip) 01209 { 01210 // Clip those paths together 01211 // Mark Howitt 31/10/00 01212 // I`ve removed the ClipPathToPathWithAutoFlatness function and replaced it with 01213 // the function that returns you a flatness value to use with the ClipPath function 01214 double ClippingFlatness = pClipPath->CalculateFlatnessValueFromPath(750.0, 2.0, 375.0); 01215 double SourceFlatness = pSrcPath->CalculateFlatnessValueFromPath(750.0, 2.0, 375.0); 01216 01217 len = pClipPath->ClipPathToPath(*pSrcPath, pDestPath, Flags, DefaultTolerance, ClippingFlatness, SourceFlatness); 01218 /* 01219 // show debugging info about the path we have clipped 01220 INT32 NumCoords = pDestPath->GetNumCoords(); 01221 PathVerb * pVerbs = pDestPath->GetVerbArray(); 01222 DocCoord * pCoord = pDestPath->GetCoordArray(); 01223 01224 for (INT32 i = 0; i < NumCoords; i++) 01225 { 01226 if (pVerbs[i] == PT_MOVETO) 01227 TRACE( _T("MOVE TO ")); 01228 else 01229 if (pVerbs[i] == PT_BEZIERTO) 01230 TRACE( _T("BEZIER TO ")); 01231 else 01232 if (pVerbs[i] == PT_LINETO) 01233 TRACE( _T("LINE TO ")); 01234 01235 TRACE( _T("%d, %d\n"), pCoord[i].x, pCoord[i].y); 01236 } 01237 TRACE( _T("end line\n")); 01238 */ 01239 } 01240 01241 return (len > 0); 01242 }
|
|
||||||||||||||||||||||||
|
This combines pClipPath with all the paths in pSelObjPathList.
Definition at line 1009 of file combshps.cpp. 01014 { 01015 // Check our input params 01016 ERROR3IF(pClipPath == NULL,"pClipPath == NULL"); 01017 ERROR3IF(pSelObjPathList == NULL,"pSelObjPathList == NULL"); 01018 if (pClipPath == NULL || pSelObjPathList == NULL) return FALSE; 01019 01020 // Get the first path in this list 01021 SelObjPathListItem* pFirstItem = pSelObjPathList->GetFirstItem(); 01022 SelObjPathListItem* pSelObjPathListItem = pFirstItem; 01023 BOOL ok = TRUE; 01024 01025 while (ok && pSelObjPathListItem != NULL) 01026 { 01027 // Get a pointer to the actual node path in this list item 01028 NodePath* pNodePath = pSelObjPathListItem->GetNodePath(); 01029 NodePath* pNewNodePath = new NodePath; 01030 NodeRenderableInk* pCreatedByNode = pSelObjPathListItem->GetCreatedByNode(); 01031 01032 if (pNodePath != NULL && pNewNodePath != NULL && pNewNodePath->SetUpPath()) 01033 { 01034 //pNewNodePath->InkPath.Initialise(pNodePath->InkPath.GetNumCoords(), 64); 01035 //if (pNewNodePath->InkPath.CopyPathDataFrom(&(pNodePath->InkPath))) 01036 if (CombinePaths(Style, pClipPath, pStrokedClipPath, &(pNodePath->InkPath), &(pNewNodePath->InkPath))) 01037 { 01038 if (bCombineEffectBitmaps) 01039 ok = DoInsertNewNode(pNewNodePath); 01040 else 01041 { 01042 if (pSelObjPathListItem==pFirstItem) 01043 { 01044 // The first path produced can live where it's originating node lived 01045 // inside whatever Effect stack was in place 01046 ok = UndoableOperation::DoInsertNewNode(pNewNodePath, pNodePath, NEXT, TRUE, FALSE, FALSE, TRUE); 01047 } 01048 else 01049 { 01050 // If more than one path is produced under an Effect node 01051 // Then we must make a new Effect Stack for it 01052 // 01053 // BUT NOTE! I don't think any multiple set of nodes are produced outside 01054 // a group at the moment - so the effect applciation code found here 01055 // has never yet been tested! 01056 Node* pInsertNode = pNodePath; 01057 ListRange* pStack = EffectsStack::GetEffectsStackFromNode(pNodePath, FALSE, TRUE, TRUE); // Include locked effects 01058 if (pStack) 01059 pInsertNode = pStack->FindLast(); 01060 ok = UndoableOperation::DoInsertNewNode(pNewNodePath, pInsertNode, NEXT, TRUE, FALSE, FALSE, TRUE); 01061 pInsertNode = pNewNodePath; 01062 delete pStack; 01063 01064 // Now copy the effects stack for this new child... 01065 if (ok) ok = ApplyEffects(pSelObjPathListItem, pNewNodePath, NULL); 01066 01067 } 01068 01069 // Select the resulting path now 01070 if (ok && pCreatedByNode->IsSelected()) 01071 pNewNodePath->Select(FALSE); 01072 01073 if (ok) 01074 { 01075 pListOfResults->AddNode(pNewNodePath); 01076 NodeInsertCount++; 01077 } 01078 } 01079 01080 // Find out who created the path, and apply its attrs to the new NodePath 01081 CCAttrMap* pAttrMap = pSelObjPathListItem->GetAttrMap(); 01082 01083 if (ok) ok = ApplyAttributes(pCreatedByNode, pNewNodePath, pAttrMap, pSelObjPathListItem); 01084 01085 // Set up a set of default path flags to enable the bezier tool to edit this node 01086 if (ok) pNewNodePath->InkPath.InitialiseFlags(); 01087 01088 if (ok) pSelObjPathList->SetProducedPaths(TRUE); 01089 } 01090 else 01091 { 01092 if (pNewNodePath!=NULL) { delete pNewNodePath; pNewNodePath = NULL; } 01093 01094 // Don't worry if the actual combine fails. We'll just not put anything in the tree 01095 // because, hmmm, I wonder.... 01096 } 01097 } 01098 else 01099 { 01100 // What? Error? Surely not! 01101 ERROR3("pNodePath == NULL || pNewNodePath == NULL || !pNewNodePath->SetUpPath())"); 01102 ok = FALSE; 01103 01104 if (pNewNodePath!=NULL) { delete pNewNodePath; pNewNodePath = NULL; } 01105 } 01106 01107 if (ok) 01108 ok = ::ContinueSlowJob(++JobCount); 01109 01110 // Get the next item in the selected object path list. 01111 pSelObjPathListItem = pSelObjPathList->GetNextItem(pSelObjPathListItem); 01112 } 01113 01114 return (ok); 01115 }
|
|
||||||||||||||||
|
Only call this if pClipPath is a line.
The shape is created by tacking on parts of the bounding rectangle to pClipPath, then closing the resultant path. Note: pDestPath must not point to pClipPath OR pSrcPath (i.e. you'll need three paths)
Definition at line 1272 of file combshps.cpp. 01273 { 01274 // Check for stupid entry parama 01275 ERROR2IF(pClipPath == NULL,FALSE,"pClipPath == NULL"); 01276 ERROR2IF(pSrcPath == NULL,FALSE,"pSrcPath == NULL"); 01277 ERROR2IF(pDestPath == NULL,FALSE,"pClipPath == NULL"); 01278 01279 // Get the coord bounds of the source path. Inflate it slightly so that we don't run into tolerance 01280 // problems when calling ClipPathToPath() 01281 //DocRect Rect = GetBoundingRect(pSrcPath); 01282 01283 // we must be consistant as to the rect we use to get a consistant shape 01284 // otherwise some items will all get cut along the line but it is luck 01285 // which side of the cut the shapes appear in (sjk 15/11/00) 01286 // DocRect Rect = GetApplication()->FindSelection()->GetBoundingRect(); // use a consistant rect for all the shapes 01287 DocRect Rect = OriginalBoundingRect; // use a consistant rect for all the shapes 01288 01289 Rect.Inflate((DefaultTolerance*2)+10); 01290 01291 INT32 NumClipCoords = pClipPath->GetNumCoords(); 01292 DocCoord* pClipCoords = pClipPath->GetCoordArray(); 01293 DocCoord ClipStart = pClipCoords[0]; // Start point of pClipPath 01294 DocCoord ClipEnd = pClipCoords[NumClipCoords-1]; // End point of pClipPath 01295 DocCoord ExtraClipStart= pClipCoords[0]; // Start point of pClipPath 01296 DocCoord ExtraClipEnd = pClipCoords[NumClipCoords-1]; // End point of pClipPath 01297 BOOL NeedExtraClipStart = FALSE; 01298 BOOL NeedExtraClipEnd = FALSE; 01299 01300 Path FlatPath; 01301 // BOOL SetFlatPath = FALSE; 01302 // double FLATTNESS = 1024; // arbitry figure of how flattened the curve will be 01303 // only used for test for extra cuts 01304 01305 // We have to choose a corner point of the bounding rect for both the start and end points 01306 // of pClipPath. 01307 01308 DocCoord ClipCornerStart,ClipCornerEnd; 01309 01310 DocCoord mid = Rect.Centre(); 01311 01312 if (ClipStart.x < mid.x) 01313 ClipCornerStart.x = Rect.lo.x; 01314 else 01315 ClipCornerStart.x = Rect.hi.x; 01316 01317 if (ClipStart.y < mid.y) 01318 ClipCornerStart.y = Rect.lo.y; 01319 else 01320 ClipCornerStart.y = Rect.hi.y; 01321 01322 if (ClipEnd.x < mid.x) 01323 ClipCornerEnd.x = Rect.lo.x; 01324 else 01325 ClipCornerEnd.x = Rect.hi.x; 01326 01327 if (ClipEnd.y < mid.y) 01328 ClipCornerEnd.y = Rect.lo.y; 01329 else 01330 ClipCornerEnd.y = Rect.hi.y; 01331 01332 // start clip point in the rect? 01333 // move it to the nearest edge 01334 if (Rect.ContainsCoord(ClipStart)) 01335 { 01336 NeedExtraClipStart = TRUE; 01337 DocCoord v = ClipStart - pClipCoords[1]; 01338 INT32 giveup = 250; // number of times to try 01339 01340 // extrapperlate the last part of the line until it breaks out of the bounding rect 01341 // give up if it fails to break out after an arbitry number of goes 01342 while (Rect.ContainsCoord(ExtraClipStart) && giveup > 0) 01343 { 01344 ExtraClipStart.x += v.x * 10; 01345 ExtraClipStart.y += v.y * 10; 01346 giveup--; 01347 } 01348 01349 // failled to leave the shape 01350 if (giveup == 0) 01351 return FALSE; 01352 01353 // moving the start may change which is the nearest corner to go for 01354 DocCoord mid = Rect.Centre(); 01355 01356 if (ExtraClipStart.x < mid.x) 01357 ClipCornerStart.x = Rect.lo.x; 01358 else 01359 ClipCornerStart.x = Rect.hi.x; 01360 01361 if (ExtraClipStart.y < mid.y) 01362 ClipCornerStart.y = Rect.lo.y; 01363 else 01364 ClipCornerStart.y = Rect.hi.y; 01365 } 01366 01367 // perform all the same calcualtions for the other end of the clip line 01368 if (Rect.ContainsCoord(ClipEnd)) 01369 { 01370 NeedExtraClipEnd = TRUE; 01371 DocCoord v = ClipEnd - pClipCoords[NumClipCoords-2]; 01372 INT32 giveup = 250; // number of times to try 01373 01374 // extrapperlate the last part of the line until it breaks out of the bounding rect 01375 // give up if it fails to break out after an arbitry number of goes 01376 while (Rect.ContainsCoord(ExtraClipEnd) && giveup > 0) 01377 { 01378 ExtraClipEnd.x += v.x * 10; 01379 ExtraClipEnd.y += v.y * 10; 01380 giveup--; 01381 } 01382 01383 // failled to leave the shape 01384 if (giveup == 0) 01385 return FALSE; 01386 01387 // moving the end may change which is the nearest corner to go for 01388 DocCoord mid = Rect.Centre(); 01389 01390 if (ExtraClipEnd.x < mid.x) 01391 ClipCornerEnd.x = Rect.lo.x; 01392 else 01393 ClipCornerEnd.x = Rect.hi.x; 01394 01395 if (ExtraClipEnd.y < mid.y) 01396 ClipCornerEnd.y = Rect.lo.y; 01397 else 01398 ClipCornerEnd.y = Rect.hi.y; 01399 } 01400 01401 // We now have two sensible corners of Rect to connect pClipPath's end points to 01402 // and if required also optimal points on this Rect boundry to that are 01403 // in direct line with the ends of the cutting line 01404 01405 // Firstly, copy pClipPath to pDestPath 01406 pDestPath->ClearPath(FALSE); 01407 if (!pDestPath->MergeTwoPaths(*pClipPath)) return FALSE; 01408 01409 // add on an extra end part to make this end of the clip path outside the bounds of the selection 01410 if (NeedExtraClipEnd) 01411 { 01412 if (!pDestPath->AddLineTo(ExtraClipEnd)) return FALSE; 01413 } 01414 01415 // Connect the end of the line to the end corner point 01416 if (!pDestPath->AddLineTo(ClipCornerEnd)) return FALSE; 01417 01418 // add in the corner nearest the end 01419 // If end corner x != start corner x, we need to connect these up 01420 if (ClipCornerEnd.x != ClipCornerStart.x) 01421 { 01422 ClipCornerEnd.x = ClipCornerStart.x; 01423 if (!pDestPath->AddLineTo(ClipCornerEnd)) return FALSE; 01424 } 01425 01426 // if the start and end corners are opposing we need to use an intermediate corner to avoid the selection 01427 // If end corner y != start corner y, we need to connect these up 01428 if (ClipCornerEnd.y != ClipCornerStart.y) 01429 { 01430 ClipCornerEnd.y = ClipCornerStart.y; 01431 if (!pDestPath->AddLineTo(ClipCornerEnd)) return FALSE; 01432 } 01433 01434 // add in the corner nearest the start 01435 // add on an extra end part to make this end of the clip path outside the bounds of the selection 01436 if (NeedExtraClipStart) 01437 { 01438 if (!pDestPath->AddLineTo(ExtraClipStart)) return FALSE; 01439 } 01440 01441 // Finally, close the path up by connecting the start corner point to the start of the line 01442 // and setting PT_CLOSEFIGURE in the last verb 01443 if (!pDestPath->AddLineTo(ClipStart)) return FALSE; 01444 01445 INT32 n = pDestPath->GetNumCoords(); 01446 PathVerb* pVerbs = pDestPath->GetVerbArray(); 01447 pVerbs[n-1] |= PT_CLOSEFIGURE; 01448 01449 return TRUE; 01450 } |