PressureSmoother Class Reference

Given a bunch of pressure samples (from a graphics tablet, or simulated from mouse movements) this class provides methods to produce a ValueFunction object representing the variable-pressure information. The pressure information is smoothed to reduce the amount of data that needs to be saved, and to improve the quality of the pressure information (e.g. to get smooth pressure-pen strokes). More...

#include <pressure.h>

List of all members.

Public Member Functions

 PressureSmoother ()
 Constructor.
 ~PressureSmoother ()
 Destructor.
ValueFunctionSmooth (Path *pSourceData, INT32 LineWidth)
 Reads raw recorded pressure information from a path and smooths it, creating a new ValueFunction object representing the pressure function.

Private Member Functions

 CC_DECLARE_MEMDUMP (PressureSmoother)


Detailed Description

Given a bunch of pressure samples (from a graphics tablet, or simulated from mouse movements) this class provides methods to produce a ValueFunction object representing the variable-pressure information. The pressure information is smoothed to reduce the amount of data that needs to be saved, and to improve the quality of the pressure information (e.g. to get smooth pressure-pen strokes).

Author; Jason

Date:
30/1/97

Definition at line 123 of file pressure.h.


Constructor & Destructor Documentation

PressureSmoother::PressureSmoother  ) 
 

Constructor.

Author; Jason

Date:
30/1/97

Definition at line 125 of file pressure.cpp.

00126 {
00127 }

PressureSmoother::~PressureSmoother  ) 
 

Destructor.

Author; Jason

Date:
30/1/97

Definition at line 141 of file pressure.cpp.

00142 {
00143 }


Member Function Documentation

PressureSmoother::CC_DECLARE_MEMDUMP PressureSmoother   )  [private]
 

ValueFunction * PressureSmoother::Smooth Path pSourceData,
INT32  LineWidth
 

Reads raw recorded pressure information from a path and smooths it, creating a new ValueFunction object representing the pressure function.

Author:
Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
Date:
21/1/97
Parameters:
pSourceData - The path containing the pressure data to smooth. [INPUTS] The pressure information should be held in the Width channel in the ExtraInfo of the path
LineWidth - The maximum "radius" of the line (half the line width) which will be used when stroking this path.

Returns:
NULL if it failed (no error is set), else a pointer to a new ValueFunction object which represents the pressure information form this path. The caller is responsible for deleting this new object when they're finished with it.
Notes: Smoothing works as follows: 1) Create a graph of the pressure samples, with pressure (y) versus position along the path (x). Store this graph in a Path.

2) Smooth the straight line segments in this graph into curve segments At present, this is done by replacing everything between 2 local minima/maxima by an S-shaped curve. This interpolation can be done by a ValueFunctionPressureS object in real-time, so we create one of them.

Definition at line 179 of file pressure.cpp.

00180 {
00181     ERROR3IF(pSourceData == NULL, "Illegal NULL param");
00182 
00183     // Find the recorded pressure values (if any)
00184     PathWidth *pWidthArray = pSourceData->GetWidthArray();
00185     if (pWidthArray == NULL)
00186         return(NULL);
00187 
00188     const INT32 NumCoords   = pSourceData->GetNumCoords();
00189     DocCoord *pCoords   = pSourceData->GetCoordArray();
00190 
00191     if (NumCoords < 2)
00192         return(NULL);
00193 
00194     // Create a ValueFunction to return. We use an "S" curve interpolated pressure function
00195     ValueFunctionPressure *pValFunc = new ValueFunctionPressureS;
00196     if (pValFunc == NULL)
00197         return(NULL);
00198 
00199     // Calculate the maximum pressure value recorded. This should be EXTRAVALUEMAX
00200     // but sometimes we seem to get bigger values.
00201     INT32 MaxPressure = pWidthArray[0];
00202     for (INT32 i = 1; i < NumCoords; i++)
00203     {
00204         if (pCoords[i].y > MaxPressure)
00205             MaxPressure = pWidthArray[i];
00206     }
00207 
00208     // If this pressure was smaller than EXTRAVALUEMAX, then we use that as the maximum,
00209     // because we don't want to scale thin strokes up to max width!
00210     if (MaxPressure < (INT32)EXTRAVALUEMAX)
00211         MaxPressure = EXTRAVALUEMAX;
00212 
00213     float Position      = 0.0f;
00214     float LastPosition  = Position;
00215     INT32 Diff          = 0;
00216     INT32 LastDiff      = pWidthArray[1] - pWidthArray[0];
00217 
00218     pValFunc->AddPressure(Position, (float)pWidthArray[0] / (float)MaxPressure);
00219 
00220     // --- Now loop through the pressure samples, scaling them into the correct range, calculating
00221     // proper "position" values for them, and smoothing the data (by replacing all points between
00222     // minima and maxima with s-shaped interpolated segments)
00223     for (INT32 Index = 1; Index < NumCoords - 1; Index++)
00224     {
00225         // Record the pressure sample. We chuck away all samples between minima/maxima
00226         // as we go, and also wheedle out any zero-length sections that might crop up.
00227         // Then the ValueFunction will interpolate between the values as it sees fit (with S-shaped curves)
00228         if (Position > LastPosition)
00229         {
00230             LastPosition = Position;
00231 
00232             Diff = pWidthArray[Index] - pWidthArray[Index - 1];
00233             if ((Diff > 0 && LastDiff <= 0) || (Diff < 0 && LastDiff >= 0))
00234             {
00235                 // We have found a min/maximum. Record this point.
00236                 pValFunc->AddPressure(Position, (float)pWidthArray[Index] / (float)MaxPressure);
00237                 LastDiff = Diff;
00238             }
00239         }
00240 
00241         // Work out approximate "travel" along the path so each width sample has a known position
00242         // [This should be calculated in the same way as in TrapEdgeList::ProcessEdgePositions, pathtrap.cpp]
00243 
00244 #if TRUE
00245         // This now simply calculates distance down the centreline.
00246         // Much faster & simpler, and it turns out it gives better results after all!
00247         const double dx = (double) (pCoords[Index-1].x - pCoords[Index].x);
00248         const double dy = (double) (pCoords[Index-1].y - pCoords[Index].y);
00249         Position += (float) sqrt((dx * dx) + (dy * dy));
00250 #else
00251     /*
00252         // Calculate the line normals to the left and right of the point
00253         NormCoord Normal1;
00254         NormCoord Normal2;
00255         Normal1.SetNormalToLine(pCoords[Index],     pCoords[Index - 1]);
00256         Normal2.SetNormalToLine(pCoords[Index + 1], pCoords[Index]);
00257 
00258         // Calculate the "left" parallel edge
00259         DocCoord P1(    pCoords[Index-1].x + (INT32)((double) LineWidth * Normal1.x),
00260                         pCoords[Index-1].y + (INT32)((double) LineWidth * Normal1.y));
00261         DocCoord P2(    pCoords[Index  ].x + (INT32)((double) LineWidth * Normal2.x),
00262                         pCoords[Index  ].y + (INT32)((double) LineWidth * Normal2.y));
00263         double dx = P1.x - P2.x;
00264         double dy = P1.y - P2.y;
00265         double LeftTravel = sqrt((dx * dx) + (dy * dy));
00266 
00267         // Calculate the "right" parallel edge
00268         P1 = DocCoord(  pCoords[Index-1].x - (INT32)((double) LineWidth * Normal1.x),
00269                         pCoords[Index-1].y - (INT32)((double) LineWidth * Normal1.y));
00270         P2 = DocCoord(  pCoords[Index  ].x - (INT32)((double) LineWidth * Normal2.x),
00271                         pCoords[Index  ].y - (INT32)((double) LineWidth * Normal2.y));
00272         dx = P1.x - P2.x;
00273         dy = P1.y - P2.y;
00274         double RightTravel = sqrt((dx * dx) + (dy * dy));
00275 
00276         // And increment Position by the larger of the 2 travel distances
00277         Position += (float)( (LeftTravel > RightTravel) ? LeftTravel : RightTravel );
00278 */
00279 #endif
00280     }
00281 
00282     // And always add a knot at the very end of the curve
00283     pValFunc->AddPressure(Position, (float)pWidthArray[NumCoords - 1] / (float)MaxPressure);
00284 
00285     pValFunc->NormalisePositions();     // And normalise all positions to lie between 0.0 and 1.0
00286 
00287     return(pValFunc);
00288 }


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