OpToggleSmooth Class Reference

When a path point is double-clicked on, this operation is invoked to toggle the smoothness of the point. This works much like the equivalent feature in ArtWorks except that making a smooth point into a cusp will change the position of the control points. More...

#include <pathedit.h>

Inheritance diagram for OpToggleSmooth:

SelOperation UndoableOperation Operation MessageHandler ListItem CCObject SimpleCCObject List of all members.

Public Member Functions

 OpToggleSmooth ()
 Constructor for toggle smooth/cusp operation.
void DoTogglePoint (NodePath *, INT32 Index, Spread *, BOOL AllSmooth, BOOL DontMoveOnCusp)
 This operation will toggle the smoothness or otherwise of a point in a path. If the point is smooth, this operation will reset the smoothing bits on any adjacent control points. It will also change their positions, making the point visibly a corner. If the point is not smooth, this operation will set the smoothing flags on the control points and perform a smoothing operation on the points. If the path consists of a single curve element and the endpoint matches the start point, nothing is smoothed since we can't make any guesses as to where the control points go.

Static Public Member Functions

static BOOL Init ()
 Adds the operation to the list of all known operations.
static OpState GetState (String_256 *Description, OpDescriptor *)
 Find out the state of the operation at the specific time.

Protected Member Functions

BOOL TogglePathPoints (NodePath *CurrentNode, INT32 Index, BOOL AllSmooth, BOOL DontMoveOnCusp)
 This operation will toggle the smoothness or otherwise of a point in a path. If the point is smooth, this operation will reset the smoothing bits on any adjacent control points. It will also change their positions, making the point visibly a corner. If the point is not smooth, this operation will set the smoothing flags on the control points and perform a smoothing operation on the points. If the path consists of a single curve element and the endpoint matches the start point, nothing is smoothed since we can't make any guesses as to where the control points go.
BOOL MakePointCusp (NodePath *CurrentNode, INT32 Index, BOOL DontMoveOnCusp)
 Makes the specified endpoint in the path a cusp join.
BOOL MakePointSmooth (NodePath *CurrentNode, INT32 Index)
 Makes the specified endpoint in the path a smooth join. Has to move the control points around the endpoint.

Detailed Description

When a path point is double-clicked on, this operation is invoked to toggle the smoothness of the point. This works much like the equivalent feature in ArtWorks except that making a smooth point into a cusp will change the position of the control points.

Author:
Jim_Lynn (Xara Group Ltd) <camelotdev@xara.com>
Date:
30/6/94

Definition at line 504 of file pathedit.h.


Constructor & Destructor Documentation

OpToggleSmooth::OpToggleSmooth  ) 
 

Constructor for toggle smooth/cusp operation.

Author:
Jim_Lynn (Xara Group Ltd) <camelotdev@xara.com>
Date:
30/6/94

Definition at line 5156 of file pathedit.cpp.

05157 {
05158     // Would initialise member variables here if there were any!
05159 }


Member Function Documentation

void OpToggleSmooth::DoTogglePoint NodePath ThisNode,
INT32  Index,
Spread pSpread,
BOOL  AllSmooth,
BOOL  DontMoveOnCusp
 

This operation will toggle the smoothness or otherwise of a point in a path. If the point is smooth, this operation will reset the smoothing bits on any adjacent control points. It will also change their positions, making the point visibly a corner. If the point is not smooth, this operation will set the smoothing flags on the control points and perform a smoothing operation on the points. If the path consists of a single curve element and the endpoint matches the start point, nothing is smoothed since we can't make any guesses as to where the control points go.

Author:
Jim_Lynn (Xara Group Ltd) <camelotdev@xara.com>/Mike/Peter
Date:
4/7/94
Parameters:
ThisNode is the nodepath containing the point we want to toggle, if it [INPUTS] is NULL then all selected paths should be scanned. Index is the index into the path of the point clicked - if part of a curve, it points at the endpoint, not the first control point. If Index is -1 then all selected endpoints on the path should be processed pSpread points at the spread containing the path AllSmooth is only needed if Index is -1. If it is then AllSmooth is TRUE if all the points should be made smooth, otherwise they are made cusps. DontMoveOnCusp is TRUE if the control points shouldn't be moved when making a cusp
- [OUTPUTS]
Returns:
-

Errors: -

See also:
-

Definition at line 5230 of file pathedit.cpp.

05231 {
05232     if (!DoStartSelOp(TRUE,TRUE))
05233     {
05234         FailAndExecute();
05235         End();
05236         return;
05237     }
05238 
05239     // We need to make sure the node or nodes that will be effected will allow this op to happen
05240     ObjChangeFlags cFlags;
05241     cFlags.TransformNode = TRUE;
05242     ObjChangeParam ObjChange(OBJCHANGE_STARTING,cFlags,NULL,this);
05243     BOOL Failed = FALSE;
05244 
05245     if (ThisNode==NULL)
05246     {
05247         // If there's no node pointer then scan the selection!
05248         SelRange*   Selected = GetApplication()->FindSelection();
05249         Node*       pNode = Selected->FindFirst();
05250         while (pNode!=NULL && !Failed)
05251         {
05252             NodePath* pSelected = pNode->IsAnEditablePath();
05253             if ( (pSelected != NULL) && (pSelected->AllowOp(&ObjChange)) )
05254             {
05255                 if (!TogglePathPoints(pSelected, Index, AllSmooth, DontMoveOnCusp))
05256                 {
05257                     InformError();
05258                     Failed = TRUE;
05259                 }
05260             }
05261             pNode = Selected->FindNext(pNode);
05262         }
05263     }
05264     else
05265     {
05266         if (ThisNode->AllowOp(&ObjChange))
05267         {
05268             if (!TogglePathPoints(ThisNode, Index, AllSmooth, DontMoveOnCusp))
05269             {
05270                 InformError();
05271                 Failed = TRUE;
05272             }
05273         }
05274     }
05275 
05276     // Update all the parents of the effected paths.
05277     if (!Failed)
05278     {
05279         ObjChange.Define(OBJCHANGE_FINISHED,cFlags,NULL,this);
05280         Failed = !UpdateChangedNodes(&ObjChange);
05281     }
05282 
05283     if (Failed)
05284         FailAndExecute();
05285 
05286     End();
05287 }

OpState OpToggleSmooth::GetState String_256 Description,
OpDescriptor
[static]
 

Find out the state of the operation at the specific time.

Author:
Jim_Lynn (Xara Group Ltd) <camelotdev@xara.com>
Date:
30/6/94
Parameters:
- [OUTPUTS]
Returns:
The state of the operation, so that menu items (ticks and greying can be done properly

Definition at line 5195 of file pathedit.cpp.

05196 {
05197     OpState Blobby;     // Ungreyed, unticked
05198     return Blobby;
05199 }

BOOL OpToggleSmooth::Init void   )  [static]
 

Adds the operation to the list of all known operations.

Author:
Jim_Lynn (Xara Group Ltd) <camelotdev@xara.com>
Date:
30/6/94
Returns:
TRUE if all went OK, FALSE otherwise

Reimplemented from SimpleCCObject.

Definition at line 5171 of file pathedit.cpp.

05172 {
05173     return (RegisterOpDescriptor(   0, 
05174                                     _R(IDS_NODEPATH_EDIT),
05175                                     CC_RUNTIME_CLASS(OpToggleSmooth), 
05176                                     OPTOKEN_NODEPATH,
05177                                     OpToggleSmooth::GetState,
05178                                     0,                                  // help ID
05179                                     _R(IDBBL_NODEPATHOP),
05180                                     0 ) );                              // bitmap ID
05181 }

BOOL OpToggleSmooth::MakePointCusp NodePath pPath,
INT32  Index,
BOOL  DontMoveOnCusp
[protected]
 

Makes the specified endpoint in the path a cusp join.

Author:
Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com> (made a function from Jim code)
Date:
10/11/95
Parameters:
pPath points to the path to modify [INPUTS] Index - the index of the path to modify DontMoveOnCusp - TRUE if the control points should not move, FALSE to position them 1/3 between prev/next endpoint
- [OUTPUTS]
Returns:
TRUE/FALSE for success/failure

Errors: Parameter checks. Creates actions which may fail

See also:
OpToggleSmooth::MakePointSmooth

Definition at line 5417 of file pathedit.cpp.

05418 {
05419     // Parameter checks
05420     ERROR2IF(pPath == NULL, FALSE, "Path pointer was NULL");
05421     ERROR2IF(Index < 0, FALSE, "Path index was negative");
05422     ERROR2IF(Index >= pPath->InkPath.GetNumCoords(), FALSE, "Path index off end of path");
05423     
05424     // Store the current state of the endpoint for undo then make it cusp
05425     ModifyElementAction* UnAction = NULL;
05426     PathFlags* Flags = NULL;
05427     PathVerb* Verbs = NULL;
05428     DocCoord* Coords = NULL;
05429     pPath->InkPath.GetPathArrays(&Verbs, &Coords, &Flags);
05430     ERROR2IF((Verbs==NULL) || (Coords==NULL) || (Flags==NULL), FALSE, "Path array pointer was NULL (panic!)");
05431     ActionCode Act = ModifyElementAction::Init(this, &UndoActions,  Verbs[Index], Flags[Index],
05432                                                                 Coords[Index], Index, pPath, (Action**)&UnAction);
05433     if (Act == AC_FAIL)
05434         return FALSE;
05435     Flags[Index].IsSmooth = FALSE;          
05436     Flags[Index].IsRotate = FALSE;
05437 
05438     // Modify the previous control point (if there is one)
05439     INT32 PrevControl = pPath->InkPath.FindPrevControlPoint(Index);
05440     if (PrevControl != -1)
05441     {
05442         Act = ModifyElementAction::Init(this, &UndoActions, Verbs[PrevControl], Flags[PrevControl],
05443                                                     Coords[PrevControl], PrevControl, pPath, (Action**)&UnAction);
05444         if (Act == AC_FAIL)
05445             return FALSE;
05446 
05447         // Move the control point if required and it is possible
05448         if (!DontMoveOnCusp && (!((Verbs[Index] == PT_MOVETO) && (Verbs[Index+1] == PT_BEZIERTO) &&
05449             (Verbs[Index+3] & PT_CLOSEFIGURE) && (Coords[Index] == Coords[Index+3]))))
05450         {
05451             Coords[PrevControl] = DocCoord::OneThird(Coords[PrevControl+1],Coords[PrevControl-2]);
05452         }
05453         Flags[PrevControl].IsSmooth = FALSE;
05454         Flags[PrevControl].IsRotate = FALSE;
05455 
05456         // Cope with the possibility that we have made the start/end of a closed
05457         // path a cusp - we can tell this if the endpoint associated with the 
05458         // previous control point is not the same as Index
05459         if (Index != PrevControl+1)
05460         {
05461             Act = ModifyElementAction::Init(this, &UndoActions, Verbs[PrevControl+1], Flags[PrevControl+1],
05462                                                 Coords[PrevControl+1], PrevControl+1, pPath, (Action**)&UnAction);
05463             if (Act == AC_FAIL)
05464                 return FALSE;
05465             Flags[PrevControl+1].IsSmooth = FALSE;
05466             Flags[PrevControl+1].IsRotate = FALSE;
05467         }
05468     }
05469 
05470     // Modify the next control point (if there is one)
05471     INT32 NextControl = pPath->InkPath.FindNextControlPoint(Index);
05472     if (NextControl != -1)
05473     {
05474         Act = ModifyElementAction::Init(this, &UndoActions, Verbs[NextControl], Flags[NextControl], 
05475                                                     Coords[NextControl], NextControl, pPath, (Action**)&UnAction);
05476         if (Act == AC_FAIL)
05477             return FALSE;
05478 
05479         // Move the control point if required and it is possible
05480         // If this is a single-segment closed curve, in which case we'll never
05481         // be able to calculate sensible points. Just clear the rotate bits
05482         if (!DontMoveOnCusp && !((Verbs[Index] == PT_MOVETO) && (Verbs[Index+1] == PT_BEZIERTO) &&
05483                                     (Verbs[Index+3] & PT_CLOSEFIGURE) && (Coords[Index] == Coords[Index+3])))
05484         {
05485             Coords[NextControl] = DocCoord::OneThird(Coords[NextControl-1], Coords[NextControl+2]);
05486         }
05487         Flags[NextControl].IsSmooth = FALSE;
05488         Flags[NextControl].IsRotate = FALSE;
05489     }
05490 
05491     return TRUE;
05492 }

BOOL OpToggleSmooth::MakePointSmooth NodePath pPath,
INT32  Index
[protected]
 

Makes the specified endpoint in the path a smooth join. Has to move the control points around the endpoint.

Author:
Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com> (made a function from Jim code)
Date:
10/11/95
Parameters:
pPath points to the path to modify [INPUTS] Index - the index of the path to modify
- [OUTPUTS]
Returns:
TRUE/FALSE for success/failure

Errors: Parameter checks. Creates actions which may fail

See also:
OpToggleSmooth::MakePointCusp

Definition at line 5510 of file pathedit.cpp.

05511 {
05512     // Parameter checks
05513     ERROR2IF(pPath == NULL, FALSE, "Path pointer was NULL");
05514     ERROR2IF(Index < 0, FALSE, "Path index was negative");
05515     ERROR2IF(Index >= pPath->InkPath.GetNumCoords(), FALSE, "Path index off end of path");
05516     
05517     // Store the current state of the endpoint for undo then make it smooth
05518     ModifyElementAction* UnAction = NULL;
05519     PathFlags* Flags = NULL;
05520     PathVerb* Verbs = NULL;
05521     DocCoord* Coords = NULL;
05522     pPath->InkPath.GetPathArrays(&Verbs, &Coords, &Flags);
05523     ERROR2IF((Verbs==NULL) || (Coords==NULL) || (Flags==NULL), FALSE, "Path array pointer was NULL (panic!)");
05524     ActionCode Act = ModifyElementAction::Init(this, &UndoActions, Verbs[Index], Flags[Index],
05525                                                                 Coords[Index], Index, pPath, (Action**)&UnAction);
05526     if (Act == AC_FAIL)
05527         return FALSE;
05528     Flags[Index].IsSmooth = TRUE;           
05529     Flags[Index].IsRotate = TRUE;
05530 
05531     // Modify the previous control point (if there is one)
05532     INT32 PrevControl = pPath->InkPath.FindPrevControlPoint(Index);
05533     if (PrevControl != -1)
05534     {
05535         Act = ModifyElementAction::Init(this, &UndoActions, Verbs[PrevControl], Flags[PrevControl],
05536                                                     Coords[PrevControl], PrevControl, pPath, (Action**)&UnAction);
05537         if (Act == AC_FAIL)
05538             return FALSE;
05539         Flags[PrevControl].IsSmooth = TRUE;
05540         Flags[PrevControl].IsRotate = TRUE;
05541         Coords[PrevControl] = pPath->InkPath.SmoothControlPoint(PrevControl);
05542 
05543         // if PrevControl+1 != Index we must be smoothing the joined ends
05544         // of a closed subpath, so we'll have to set the smoothing bits on this point too
05545         if (Index != PrevControl+1)
05546         {
05547             Act = ModifyElementAction::Init(this, &UndoActions, Verbs[PrevControl+1], Flags[PrevControl+1],
05548                                                 Coords[PrevControl+1], PrevControl+1, pPath, (Action**)&UnAction);
05549             if (Act == AC_FAIL)
05550                 return FALSE;
05551             Flags[PrevControl+1].IsSmooth = TRUE;
05552             Flags[PrevControl+1].IsRotate = TRUE;
05553         }
05554     }
05555 
05556     // Modify the next control point (if there is one)
05557     INT32 NextControl = pPath->InkPath.FindNextControlPoint(Index);
05558     if (NextControl != -1)
05559     {
05560         Act = ModifyElementAction::Init(this, &UndoActions, Verbs[NextControl], Flags[NextControl],
05561                                                     Coords[NextControl], NextControl, pPath, (Action**)&UnAction);
05562         if (Act == AC_FAIL)
05563             return FALSE;
05564         Flags[NextControl].IsSmooth = TRUE;
05565         Flags[NextControl].IsRotate = TRUE;
05566         Coords[NextControl] = pPath->InkPath.SmoothControlPoint(NextControl);
05567     }
05568 
05569     return TRUE;
05570 }

BOOL OpToggleSmooth::TogglePathPoints NodePath CurrentNode,
INT32  Index,
BOOL  AllSmooth,
BOOL  DontMoveOnCusp
[protected]
 

This operation will toggle the smoothness or otherwise of a point in a path. If the point is smooth, this operation will reset the smoothing bits on any adjacent control points. It will also change their positions, making the point visibly a corner. If the point is not smooth, this operation will set the smoothing flags on the control points and perform a smoothing operation on the points. If the path consists of a single curve element and the endpoint matches the start point, nothing is smoothed since we can't make any guesses as to where the control points go.

Author:
Jim_Lynn (Xara Group Ltd) <camelotdev@xara.com>
Date:
4/7/94
Parameters:
ThisNode is the nodepath containing the point we want to toggle. [INPUTS] Index is the index into the path of the point clicked - if part of a curve, it points at the endpoint, not the first control point. If Index is -1 then all selected endpoints on the path should be processed AllSmooth is only needed if Index is -1. If it is then AllSmooth is TRUE if all the points should be made smooth, otherwise they are made cusps.
- [OUTPUTS]
Returns:
FALSE if an error occured

Errors: -

See also:
-

Definition at line 5316 of file pathedit.cpp.

05317 {
05318     ERROR2IF(CurrentNode==NULL, FALSE, "Path pointer was NULL");
05319 
05320     PathFlags* Flags = NULL;
05321     PathVerb* Verbs = NULL;
05322     DocCoord* Coords = NULL;
05323     CurrentNode->InkPath.GetPathArrays(&Verbs, &Coords, &Flags);
05324     ERROR2IF((Verbs==NULL) || (Coords==NULL) || (Flags==NULL), FALSE, "Path array pointer was NULL (panic!)");
05325 
05326     INT32 NumCoords = CurrentNode->InkPath.GetNumCoords();
05327     INT32 LowIndex  = (Index == -1) ? 0 : Index;
05328     INT32 HighIndex = (Index == -1) ? NumCoords-1 : Index;
05329 
05330     // Check to see if this is a single-segment closed curve, in which case we'll never
05331     // be able to smooth it. We can only be on the moveto...
05332     if ( (Verbs[0] == PT_MOVETO) && (Verbs[1] == PT_BEZIERTO) && (Verbs[3] & PT_CLOSEFIGURE) &&
05333           (Coords[0] == Coords[3]) && (!Flags[0].IsRotate) )
05334         return TRUE;
05335 
05336     BOOL Success = TRUE;
05337     BOOL ChangedThisPath = FALSE;
05338     for (INT32 CurrentIndex = LowIndex; (CurrentIndex <= HighIndex) && Success; CurrentIndex++)
05339     {
05340         BOOL Test = FALSE;      // TRUE if this endpoint should be toggled
05341         CurrentNode->InkPath.GetPathArrays(&Verbs, &Coords, &Flags);
05342 
05343         if (HighIndex != LowIndex)
05344         {
05345             if (Flags[CurrentIndex].IsEndPoint && Flags[CurrentIndex].IsSelected)
05346             {   // Force selected point to be either cusp or smooth
05347                 if (AllSmooth)
05348                     Test = !(Flags[CurrentIndex].IsRotate);
05349                 else
05350                     Test = Flags[CurrentIndex].IsRotate;
05351             }
05352             else
05353                 Test = FALSE;
05354         }
05355         else
05356         {   // Toggle single point
05357             Test = Flags[CurrentIndex].IsEndPoint;
05358         }
05359         
05360         // Toggle the smooth state of this endpoint
05361         if (Test)
05362         {
05363             ERROR3IF(!Flags[CurrentIndex].IsEndPoint, "Attempting to toggle a control point");
05364 
05365             // Force a re-draw of the place where the path used to be
05366             if (Success && !ChangedThisPath)
05367             {
05368                 Success = (RecalcBoundsAction::DoRecalc(this, &UndoActions, CurrentNode) != AC_FAIL);
05369 //              // Store the paths sub-selection state
05370 //              if (Success)
05371 //                  Success = (StorePathSubSelStateAction::DoRecord(this, &UndoActions, &CurrentNode->InkPath) != AC_FAIL);
05372             
05373                 ChangedThisPath = TRUE;
05374             }
05375 
05376             // Now let's adjust the smoothness of this point.
05377             if (Success)
05378             {
05379                 CurrentNode->InkPath.GetPathArrays(&Verbs, &Coords, &Flags);
05380                 if (Flags[CurrentIndex].IsRotate)
05381                     Success = MakePointCusp(CurrentNode, CurrentIndex, DontMoveOnCusp);
05382                 else
05383                     Success = MakePointSmooth(CurrentNode, CurrentIndex);
05384             }
05385         }
05386     }
05387 
05388     // Now create a RecordBoundsAction so that the action list has bounds recalculation
05389     // at both ends which ensures undo and redo both work properly
05390     if (Success && ChangedThisPath)
05391     {
05392         CurrentNode->InvalidateBoundingRect();
05393         GetApplication()->FindSelection()->UpdateBounds();
05394         Success = (RecordBoundsAction::DoRecord(this, &UndoActions, CurrentNode) != AC_FAIL);
05395     }
05396 
05397     return Success;
05398 }


The documentation for this class was generated from the following files:
Generated on Sat Nov 10 03:59:09 2007 for Camelot by  doxygen 1.4.4