BOOL FreeHandEPSFilter::AddNewNode(Node *pNewNode) { if(IS_A(pNewNode, NodePath)) pLastPathSeen = (NodePath *)pNewNode; // check to see if we want to handle this if((ComplexPathMode == FALSE) || (pNewNode == 0) || (pNode == 0) || (!IS_A(pNewNode, NodePath))) return EPSFilter::AddNewNode(pNewNode); // check to see if this is the first... if(HadFirstOfComplexPath == FALSE) { HadFirstOfComplexPath = TRUE; return EPSFilter::AddNewNode(pNewNode); } // find the last child of the node Node *pLastChild = pNode->FindLastChild(); if(pLastChild == 0 || !IS_A(pLastChild, NodePath)) return EPSFilter::AddNewNode(pNewNode); // we know that both of these things are NodePaths. Path *pTarget = &((NodePath *)pLastChild)->InkPath; Path *pAddition = &((NodePath *)pNewNode)->InkPath; // work out the new flags for the target BOOL TargetFilled = pTarget->IsFilled; BOOL TargetStroked = pTarget->IsStroked; if(pAddition->IsFilled) TargetFilled = TRUE; if(pAddition->IsStroked) TargetStroked = TRUE; // add this new path to the old one... if(!pTarget->MergeTwoPaths(*pAddition)) return FALSE; // check that the thing we just added isn't already there if(!RemoveLastSubPathIfNotUnique(pTarget)) return FALSE; // set it's flags pTarget->IsFilled = TargetFilled; pTarget->IsStroked = TargetStroked; // vape it's attributes pLastChild->DeleteChildren(pLastChild->FindFirstChild()); // apply some new ones SetPathFilled(TargetFilled); if(!AddAttributes((NodePath *)pLastChild, TargetStroked, TargetFilled)) return FALSE; // hide the nice additional path //if(!ImportInfo.pOp->DoHideNode(pNewNode, TRUE)) // return FALSE; pNewNode->CascadeDelete(); delete pNewNode; // set the last seen path bollox pLastPathSeen = (NodePath *)pLastChild; // done! return TRUE; }
/******************************************************************************************** > BOOL BlendHelpers::BlendPaths(BlendNodeParam * pParam, Path * pPath) Author: David_McClarnon (Xara Group Ltd) <*****@*****.**> Created: 21/2/2000 Inputs: The blend node parameter Outputs: The blended path is stored in three arrays: the coords, the verbs, and the flags. The arrays are: pTempCoords pTempVerbs pTempFlags ArrayLength = the length of all three arrays This allows the caller to decide what to do with the blended path in a very flexible way. Returns: TRUE if successful, FALSE otherwise Purpose: Blends two BlendPath objects by the amount specified in BlendRatio SeeAlso: - ********************************************************************************************/ BOOL BlendHelpers::BlendPaths(BlendNodeParam * pParam, Path * pPath) { // Check entry params BlendPath * pBlendPathStart = pParam->GetStartBlendPath(); BlendPath * pBlendPathEnd = pParam->GetEndBlendPath(); ERROR2IF(!pBlendPathStart->GetBlendNode()->IsNodePath(), FALSE, "Start blend path's node isn't a node path"); ERROR2IF(!pBlendPathEnd->GetBlendNode()->IsNodePath(), FALSE, "End blend path's node isn't a node path"); BOOL ok = (pBlendPathStart != NULL && pBlendPathEnd != NULL); if (ok) ok = (pBlendPathStart->GetBlendNode() != NULL && pBlendPathEnd->GetBlendNode() != NULL); ERROR3IF(!ok,"One or more NULL entry params"); if (!ok) return FALSE; // Get the types of the two paths PathTypeEnum PathTypeStart = pBlendPathStart->GetPathType(); PathTypeEnum PathTypeEnd = pBlendPathEnd ->GetPathType(); // The blended path will be closed if either of the paths is a shape BOOL Closed = (PathTypeStart == PATHTYPE_SHAPE) || (PathTypeEnd == PATHTYPE_SHAPE); Path * pPathStart = NULL; // Find the paths associated with the start and end blend paths if (pBlendPathStart->GetBlendNode()->IsNodePath()) { pPathStart = &(((NodePath *)pBlendPathStart->GetBlendNode())->InkPath); } Path * pPathEnd = NULL; if (pBlendPathEnd->GetBlendNode()->IsNodePath()) { pPathEnd = &(((NodePath *)pBlendPathEnd->GetBlendNode())->InkPath); } // Calculate how large the arrays have to be to store the blended path definition INT32 DestPathSize = ((pPathStart->GetNumCoords()+pPathEnd->GetNumCoords())*3)+500; // Get some arrays used to hold the blended path data, and error if any are NULL DocCoord* pDestCoords = GetCoordArray(DestPathSize); PathVerb* pDestVerbs = GetVerbArray(DestPathSize); PathFlags* pDestFlags = GetFlagArray(DestPathSize); UINT32* pBuff = GetGBlendBuff(DestPathSize); if (pDestCoords == NULL || pDestVerbs == NULL || pDestFlags == NULL || pBuff == NULL) return FALSE; // This section copes with the case when blending a line with a shape. // In this case we need to get a temp path the is actually a shape version of the line. // The line is simply reversed back onto itself to form a shape that would look identical to the // line if rendered. This allows the line to appear to open up to the shape when blended. Path Shape; if (PathTypeStart != PathTypeEnd) { BOOL ok = FALSE; if (!Shape.Initialise()) return FALSE; // if going from a line to a shape, convert the start path to a shape if (PathTypeStart == PATHTYPE_LINE && PathTypeEnd == PATHTYPE_SHAPE) { ok = NodeBlender::ConvertLineToShape(pPathStart,&Shape); pPathStart = &Shape; } // if going from a shape to a line, convert the end path to a shape if (PathTypeStart == PATHTYPE_SHAPE && PathTypeEnd == PATHTYPE_LINE) { ok = NodeBlender::ConvertLineToShape(pPathEnd,&Shape); pPathEnd = &Shape; } if (!ok) return FALSE; } // The blend should do a one-to-one mapping when the OneToOne flag is set AND both paths // have the same number of elements BOOL OneToOne = FALSE; if (pParam->GetOneToOne()) OneToOne = (pBlendPathStart->GetNumElements() == pBlendPathEnd->GetNumElements()); // Now actually blend the two paths GBlend GBlendObj; // Define the blend GBlendObj.Define( (PPOINT)pPathStart->GetCoordArray(), // Specify the start path pPathStart->GetVerbArray(), pPathStart->GetNumCoords(), (PPOINT)pPathEnd ->GetCoordArray(), // Specify the end path pPathEnd ->GetVerbArray(), pPathEnd ->GetNumCoords(), OneToOne, // The one-to-one flag 1024, // Flatness pBuff, // Buffer for GBlend to use DestPathSize*sizeof(UINT32)); // The buffer size // Blend the paths m_ArrayLength = GBlendObj.Blend(pParam->GetBlendRatio(), // The blend ratio, 0.0 < BlendRatio < 1.0 (PPOINT)pDestCoords, // Array to store blended coords pDestVerbs, // Array to store blended verbs DestPathSize); // The num elements in the two arrays // If we're blending a line to another line, we need to make sure that the blended line // is going in a direction that corresponds to the source lines. This ensures attributes // that depend on this direction (e.g. start and end arrows) look correct. // // When creating blend paths of lines, we can detect if the blend path has been reversed, // in relation to the original path, by the original mapping value. // If it's 0 it has NOT been reversed, otherwise it's been reversed. // // If the blend ratio is <=0.5, the blended path is closest to the start blend path, // so we look at the start blend path's original mapping. // // If blend ration > 0.5, look at the end blend path's original mapping. // // The (BlendRation <= 0.5) cut-off point is the same as the cut-off point used in the blending // of attributes. if (pBlendPathStart->IsLine() && pBlendPathEnd->IsLine()) { BlendPath* pBlendPath; if (pParam->GetBlendRatio() <= 0.5) pBlendPath = pBlendPathStart; else pBlendPath = pBlendPathEnd; if (pBlendPath->GetOrigMapping() != 0) NodeBlender::ReversePath(pDestCoords,pDestVerbs,m_ArrayLength); } // We need to do some work on the blended path if (!NodeBlender::ProcessBlendedPath(pDestCoords,pDestVerbs,pDestFlags,m_ArrayLength,Closed)) return FALSE; Path RetnPath; RetnPath.Initialise(m_ArrayLength); BOOL Filled = pPathStart->IsFilled || pPathEnd->IsFilled; BOOL Stroked = pPathStart->IsStroked || pPathEnd->IsStroked; RetnPath.MergeTwoPaths(pDestCoords,pDestVerbs,pDestFlags,m_ArrayLength,Filled); pPath->ClearPath(); pPath->CloneFrom(RetnPath); pPath->IsFilled = Filled; pPath->IsStroked = Stroked; return TRUE; }