00001 // $Id: valfunc.cpp 1517 2006-07-24 21:05:42Z gavin $ 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 // Implementation of ValueFunction classes (used in stroke providing) 00099 00100 #include "camtypes.h" 00101 00102 #include <math.h> 00103 #include "valfunc.h" 00104 00105 #include "cxftags.h" 00106 //#include "cxfrec.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00107 //#include "fixmem.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00108 //#include "list.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00109 00110 00111 CC_IMPLEMENT_DYNAMIC(ValueFunction, ListItem) 00112 CC_IMPLEMENT_DYNAMIC(ValueFunctionConstant, ValueFunction) 00113 CC_IMPLEMENT_DYNAMIC(ValueFunctionRandom, ValueFunction) 00114 CC_IMPLEMENT_DYNAMIC(ValueFunctionRamp, ValueFunction) 00115 CC_IMPLEMENT_DYNAMIC(ValueFunctionRampLinear, ValueFunctionRamp) 00116 CC_IMPLEMENT_DYNAMIC(ValueFunctionRampS, ValueFunctionRamp) 00117 CC_IMPLEMENT_DYNAMIC(ValueFunctionRampS2, ValueFunctionRamp) 00118 CC_IMPLEMENT_DYNAMIC(ValueFunctionRampL, ValueFunctionRamp) 00119 CC_IMPLEMENT_DYNAMIC(ValueFunctionRampL2, ValueFunctionRamp) 00120 CC_IMPLEMENT_DYNAMIC(ValueFunctionDoubleRampS, ValueFunctionRamp) 00121 CC_IMPLEMENT_DYNAMIC(ValueFunctionSawTooth, ValueFunctionRamp) 00122 CC_IMPLEMENT_DYNAMIC(ValueFunctionPropeller, ValueFunctionRamp) 00123 CC_IMPLEMENT_DYNAMIC(ValueFunctionIntestine, ValueFunctionRamp) 00124 CC_IMPLEMENT_DYNAMIC(ValueFunctionDecay, ValueFunctionRamp) 00125 CC_IMPLEMENT_DYNAMIC(ValueFunctionBevelEnds, ValueFunctionRamp) 00126 CC_IMPLEMENT_DYNAMIC(ValueFunctionBlip, ValueFunction) 00127 CC_IMPLEMENT_DYNAMIC(ValueFunctionTeardrop, ValueFunctionBlip) 00128 CC_IMPLEMENT_DYNAMIC(ValueFunctionTeardropCurvedEnd, ValueFunctionBlip) 00129 CC_IMPLEMENT_DYNAMIC(ValueFunctionEllipse, ValueFunctionBlip) 00130 CC_IMPLEMENT_DYNAMIC(ValueFunctionThumbtack, ValueFunctionBlip) 00131 CC_IMPLEMENT_DYNAMIC(ValueFunctionPressure, ValueFunction) 00132 CC_IMPLEMENT_DYNAMIC(ValueFunctionPressureS, ValueFunctionPressure) 00133 CC_IMPLEMENT_DYNAMIC(ValueFunctionSmoothStroke, ValueFunction) 00134 CC_IMPLEMENT_DYNAMIC(ValueFunctionSS_Yacht, ValueFunctionSmoothStroke) 00135 CC_IMPLEMENT_DYNAMIC(ValueFunctionSS_Iron, ValueFunctionSmoothStroke) 00136 CC_IMPLEMENT_DYNAMIC(ValueFunctionSS_Reed, ValueFunctionSmoothStroke) 00137 CC_IMPLEMENT_DYNAMIC(ValueFunctionSS_Meteor, ValueFunctionSmoothStroke) 00138 CC_IMPLEMENT_DYNAMIC(ValueFunctionSS_Petal, ValueFunctionSmoothStroke) 00139 CC_IMPLEMENT_DYNAMIC(ValueFunctionSS_Comet, ValueFunctionSmoothStroke) 00140 CC_IMPLEMENT_DYNAMIC(ValueFunctionSS_Fallout, ValueFunctionSmoothStroke) 00141 CC_IMPLEMENT_DYNAMIC(ValueFunctionSS_Torpedo, ValueFunctionSmoothStroke) 00142 CC_IMPLEMENT_DYNAMIC(ValueFunctionSS_Missile, ValueFunctionSmoothStroke) 00143 CC_IMPLEMENT_DYNAMIC(ValueFunctionSS_Convex, ValueFunctionSmoothStroke) 00144 CC_IMPLEMENT_DYNAMIC(ValueFunctionSS_Concave, ValueFunctionSmoothStroke) 00145 CC_IMPLEMENT_DYNAMIC(ValueFunctionSS_SlimBlip, ValueFunctionSmoothStroke) 00146 CC_IMPLEMENT_DYNAMIC(ValueFunctionSS_Cigar, ValueFunctionSmoothStroke) 00147 CC_IMPLEMENT_DYNAMIC(ValueFunctionSS_Cigar2, ValueFunctionSmoothStroke) 00148 CC_IMPLEMENT_DYNAMIC(ValueFunctionSS_Cigar3, ValueFunctionSmoothStroke) 00149 CC_IMPLEMENT_DYNAMIC(ValueFunctionSS_OceanLiner,ValueFunctionSmoothStroke) 00150 CC_IMPLEMENT_DYNAMIC(ValueFunctionSS_Goldfish, ValueFunctionSmoothStroke) 00151 CC_IMPLEMENT_DYNAMIC(ValueFunctionSS_Barb, ValueFunctionSmoothStroke) 00152 00153 00154 // Declare smart memory handling in Debug builds 00155 #define new CAM_DEBUG_NEW 00156 00157 00158 const double Pi = 3.141592654; 00159 00160 bool ValueFunctionSS_Yacht::bMadeTable = false; 00161 bool ValueFunctionSS_Iron::bMadeTable = false; 00162 bool ValueFunctionSS_Reed::bMadeTable = false; 00163 bool ValueFunctionSS_Meteor::bMadeTable = false; 00164 bool ValueFunctionSS_Petal::bMadeTable = false; 00165 bool ValueFunctionSS_Comet::bMadeTable = false; 00166 bool ValueFunctionSS_Fallout::bMadeTable = false; 00167 bool ValueFunctionSS_Torpedo::bMadeTable = false; 00168 bool ValueFunctionSS_Missile::bMadeTable = false; 00169 bool ValueFunctionSS_Convex::bMadeTable = false; 00170 bool ValueFunctionSS_Concave::bMadeTable = false; 00171 bool ValueFunctionSS_SlimBlip::bMadeTable = false; 00172 bool ValueFunctionSS_Cigar::bMadeTable = false; 00173 bool ValueFunctionSS_Cigar2::bMadeTable = false; 00174 bool ValueFunctionSS_Cigar3::bMadeTable = false; 00175 bool ValueFunctionSS_OceanLiner::bMadeTable = false; 00176 bool ValueFunctionSS_Goldfish::bMadeTable = false; 00177 bool ValueFunctionSS_Barb::bMadeTable = false; 00178 00179 //Used by the Smooth-Stroke Functions to retain bezier data... 00180 double ValueFunctionSmoothStroke::xvalue[18][256]; 00181 double ValueFunctionSmoothStroke::yvalue[18][256]; 00182 00183 00184 00186 // ValueFunction base class 00188 00189 00190 List ValueFunction::RegisteredFunctions; 00191 00192 00193 /****************************************************************************************** 00194 00195 > static BOOL ValueFunction::Init(void) 00196 00197 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00198 Created: 27/1/97 00199 00200 Returns: TRUE if it initialises successfully 00201 00202 Purpose: Initialises all valueFunction classes defined in valfunc.cpp 00203 00204 Adds an instance of each ValueFunction to a dynamic list, which is 00205 used to create new ValueFunctions as they are loaded from files. 00206 Any dynamically added ValueFunction-derived class should add an 00207 instance to the RegistreredFunctions list in order to properly 00208 handle being re-loaded. 00209 00210 ******************************************************************************************/ 00211 00212 BOOL ValueFunction::Init(void) 00213 { 00214 #define VFINIT(TYPE) \ 00215 { \ 00216 TYPE *pFunc = new TYPE; \ 00217 if (!pFunc) \ 00218 return(FALSE); \ 00219 RegisteredFunctions.AddTail(pFunc); \ 00220 } 00221 00222 VFINIT(ValueFunctionConstant); 00223 VFINIT(ValueFunctionRandom); 00224 VFINIT(ValueFunctionRampLinear); 00225 VFINIT(ValueFunctionRampS); 00226 VFINIT(ValueFunctionPressure); 00227 VFINIT(ValueFunctionPressureS); 00228 VFINIT(ValueFunctionBlip); 00229 VFINIT(ValueFunctionTeardrop); 00230 VFINIT(ValueFunctionEllipse); 00231 VFINIT(ValueFunctionThumbtack); 00232 VFINIT(ValueFunctionRampL); 00233 VFINIT(ValueFunctionRampS2); 00234 VFINIT(ValueFunctionRampL2); 00235 VFINIT(ValueFunctionTeardropCurvedEnd); 00236 VFINIT(ValueFunctionSawTooth); 00237 VFINIT(ValueFunctionPropeller); 00238 VFINIT(ValueFunctionDoubleRampS); 00239 VFINIT(ValueFunctionIntestine); 00240 VFINIT(ValueFunctionDecay); 00241 VFINIT(ValueFunctionBevelEnds); 00242 VFINIT(ValueFunctionSS_Reed); 00243 VFINIT(ValueFunctionSS_Meteor); 00244 VFINIT(ValueFunctionSS_Petal); 00245 VFINIT(ValueFunctionSS_Comet); 00246 VFINIT(ValueFunctionSS_Barb); 00247 VFINIT(ValueFunctionSS_Concave); 00248 VFINIT(ValueFunctionSS_Convex); 00249 VFINIT(ValueFunctionSS_Iron); 00250 VFINIT(ValueFunctionSS_Torpedo); 00251 VFINIT(ValueFunctionSS_Missile); 00252 VFINIT(ValueFunctionSS_Goldfish); 00253 VFINIT(ValueFunctionSS_OceanLiner); 00254 VFINIT(ValueFunctionSS_Yacht); 00255 VFINIT(ValueFunctionSS_SlimBlip); 00256 VFINIT(ValueFunctionSS_Cigar); 00257 VFINIT(ValueFunctionSS_Cigar2); 00258 VFINIT(ValueFunctionSS_Cigar3); 00259 VFINIT(ValueFunctionSS_Fallout); 00260 00261 #undef VFINIT 00262 00263 return(TRUE); 00264 } 00265 00266 00267 00268 /****************************************************************************************** 00269 00270 > static void ValueFunction::DeInit(void) 00271 00272 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00273 Created: 27/1/97 00274 00275 Returns: TRUE if it initialises successfully 00276 00277 Purpose: Initialises all valueFunction classes defined in valfunc.cpp 00278 00279 ******************************************************************************************/ 00280 00281 void ValueFunction::DeInit(void) 00282 { 00283 RegisteredFunctions.DeleteAll(); 00284 } 00285 00286 00287 00288 /****************************************************************************************** 00289 00290 > virtual BOOL ValueFunction::IsDifferent(ValueFunction *Other) 00291 00292 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00293 Created: 8/1/97 00294 00295 Inputs: pOther - Another ValueFunction object to compare this one to 00296 00297 Returns: TRUE if the objects are considered different, 00298 FALSE if they are considered identical 00299 00300 Purpose: Comparator. 00301 Determines if 2 different ValueFunction objects are considered 00302 different. 00303 00304 Notes: The base class simply checks if they are of the same runtime class 00305 and returns TRUE if they are not. Derived classes which can differ 00306 in content between instances must override this method. 00307 00308 ******************************************************************************************/ 00309 00310 BOOL ValueFunction::IsDifferent(ValueFunction *pOther) 00311 { 00312 ERROR3IF(pOther == NULL, "Illegal NULL param"); 00313 return(GetRuntimeClass() != pOther->GetRuntimeClass()); 00314 } 00315 00316 00317 00318 /****************************************************************************************** 00319 00320 > static ValueFunction *ValueFunction::ReadFileRecord(CXaraFileRecord *pInputRecord) 00321 00322 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00323 Created: 27/1/97 00324 00325 Inputs: pInputRecord - The file record to read from 00326 00327 Returns: NULL if it fails, else a pointer to a new object initialised from 00328 the given file record. 00329 00330 Purpose: Main entry point for loading ValueFunctions from files. The caller 00331 record handler passes the record in to this static function, and 00332 the saved VF is re-constituted from the saved information. On return 00333 the caller can read any extra values that they saved in the record. 00334 00335 Notes: This scans the member RegisteredFunction list to see if it can find 00336 a ValueFunction of the appropriate type, and asks it to create a new 00337 ValueFunction to be initialised from the given record (by calling 00338 the virtual CreateAndReadFileRecord()) 00339 00340 ******************************************************************************************/ 00341 00342 ValueFunction *ValueFunction::ReadFileRecord(CXaraFileRecord *pInputRecord) 00343 { 00344 ERROR3IF(pInputRecord == NULL, "Illegal NULL params"); 00345 00346 INT32 ID; 00347 pInputRecord->ReadINT32(&ID); 00348 00349 ValueFunction *pFunc = (ValueFunction *) RegisteredFunctions.GetHead(); 00350 while (pFunc != NULL) 00351 { 00352 if (pFunc->GetUniqueID() == ID) 00353 return(pFunc->CreateAndReadFileRecord(pInputRecord)); 00354 00355 pFunc = (ValueFunction *) RegisteredFunctions.GetNext(pFunc); 00356 } 00357 00358 return(NULL); 00359 } 00360 00361 00362 00363 /****************************************************************************************** 00364 00365 > virtual CamelotFileRecord *ValueFunction::CreateAndWriteFileRecord(INT32 RecordTag, 00366 INT32 DerivedBytes, INT32 ExtraBytes, 00367 BaseCamelotFilter *pFilter) 00368 00369 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00370 Created: 27/1/97 00371 00372 Inputs: RecordTag - the tag to write this record under 00373 00374 DerivedBytes- The number of bytes of information the derived VF 00375 class wishes to write to save its state. Space 00376 for this infomation will be reserved in the new record 00377 00378 ExtraBytes - The number of extra bytes of information the caller 00379 will write into the record after caling this function 00380 (Space for this many extra bytes will be reserved by 00381 this function when it creates the new file record) 00382 This may be 0 or more bytes. 00383 00384 pFilter - The filter to write to 00385 00386 Returns: NULL if it failed, else a pointer to a record which saves the state 00387 of this valueFunction object. Once the caller has written the record, 00388 they MUST DELETE it. 00389 00390 This base-class function only writes the ValueFunction header for 00391 the record data. The caller must append its own state information 00392 to this header - see the record description below. 00393 00394 Purpose: Creates an output record containing an embedded ValueFunction description. 00395 00396 The record will be (4 + DerivedBytes + ExtraBytes) bytes in length, and 00397 on return from this function, the first 4 bytes (only) will have been 00398 written. The caller(s) must fill in the remainder. 00399 00400 All ValueFunction record data has 3 sections, whiich are recorded as follows: 00401 1. ValueFunction header, identifying which type of VF is being saved. 00402 This is written by the base class CreateAndWriteFileRecord 00403 INT32 ValueFunctionUniqueID (4 bytes) 00404 00405 2. Derived-class-data (0 or more bytes). This is written by the derived 00406 class WriteFileRecord function, into the record returned from here. 00407 This data must be DerivedBytes (0 or more) bytes in length. 00408 00409 3. Caller data. This is written by the caller of the derived function. 00410 This data must be ExtraBytes (0 or more) bytes in length. 00411 00412 SeeAlso: ValueFunctionConstant::CreateAndReadFileRecord 00413 00414 ******************************************************************************************/ 00415 00416 CamelotFileRecord *ValueFunction::CreateAndWriteFileRecord(INT32 RecordTag, 00417 INT32 DerivedBytes, INT32 ExtraBytes, 00418 BaseCamelotFilter *pFilter) 00419 { 00420 ERROR3IF(pFilter == NULL, "Illegal NULL param"); 00421 ERROR3IF(ExtraBytes < 0, "Stupid ExtraBytes request in ValueFunction::CreateAndWriteFileRecord"); 00422 00423 // Calculate how many bytes of information this VF will write. 00424 // We write a 4-byte "header", followed by the derived class data and the caller data 00425 const INT32 RecordSize = 4 + DerivedBytes + ExtraBytes; 00426 00427 // Create an appropriate record, and write the header info to it 00428 CamelotFileRecord *pRec = new CamelotFileRecord(pFilter, RecordTag, RecordSize); 00429 00430 // If that worked, then we now init & add our own data to the record 00431 if (pRec != NULL) 00432 { 00433 BOOL ok = pRec->Init(); 00434 if (ok) ok = pRec->WriteUINT32(GetUniqueID()); 00435 00436 if (!ok) // If we failed, then clean up & return NULL 00437 { 00438 delete pRec; 00439 pRec = NULL; 00440 } 00441 } 00442 00443 return(pRec); 00444 } 00445 00446 00447 00448 00449 00451 // ValueFunctionConstant class 00453 00454 /****************************************************************************************** 00455 00456 > ValueFunctionConstant::ValueFunctionConstant(double Value) 00457 00458 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00459 Created: 30/12/96 00460 00461 Inputs: Value - The value to be used at all positions 00462 00463 Purpose: Constructor 00464 The Constant ValueFunction always returns the same value! 00465 00466 ******************************************************************************************/ 00467 00468 ValueFunctionConstant::ValueFunctionConstant(double Value) 00469 { 00470 Value1 = Value; 00471 } 00472 00473 00474 00475 /****************************************************************************************** 00476 00477 > virtual double ValueFunctionConstant::GetValue(double Position) 00478 00479 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00480 Created: 30/12/96 00481 00482 Inputs: Position - A value between 0.0 and 1.0 00483 Returns: A constant value (Value, as given in the constructor) representing 00484 the value of the function at the given Position. 00485 00486 Purpose: To read the value of this function at a given position 00487 00488 Notes: Constant is a bit simple - it always returns the same value 00489 00490 ******************************************************************************************/ 00491 00492 double ValueFunctionConstant::GetValue(double Position) 00493 { 00494 return(Value1); 00495 } 00496 00497 00498 00499 /****************************************************************************************** 00500 00501 > virtual ValueFunction *ValueFunctionConstant::Clone(void) 00502 00503 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00504 Created: 8/1/97 00505 00506 Returns: NULL if it failed, else an exact copy of this object 00507 00508 Purpose: Clone operator. Creates an exact copy of this object 00509 00510 ******************************************************************************************/ 00511 00512 ValueFunction *ValueFunctionConstant::Clone(void) 00513 { 00514 ValueFunction *pClone = new ValueFunctionConstant(Value1); 00515 return(pClone); 00516 } 00517 00518 00519 00520 /****************************************************************************************** 00521 00522 > virtual BOOL ValueFunctionConstant::IsDifferent(ValueFunction *Other) 00523 00524 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00525 Created: 8/1/97 00526 00527 Inputs: pOther - Another ValueFunction object to compare this one to 00528 00529 Returns: TRUE if the objects are considered different, 00530 FALSE if they are considered identical 00531 00532 Purpose: Comparator. 00533 Determines if 2 different ValueFunction objects are considered 00534 different. 00535 00536 Notes: Calls the base class to see if they are different classes, 00537 and then compares identical classes by checking member vars 00538 00539 ******************************************************************************************/ 00540 00541 BOOL ValueFunctionConstant::IsDifferent(ValueFunction *pOther) 00542 { 00543 if (ValueFunction::IsDifferent(pOther)) 00544 return(TRUE); 00545 00546 // Both objects are instances of this class, so compare them more carefully 00547 return(Value1 != ((ValueFunctionConstant *)pOther)->Value1); 00548 } 00549 00550 00551 00552 /****************************************************************************************** 00553 00554 > virtual CamelotFileRecord *ValueFunctionConstant::WriteFileRecord(INT32 RecordTag, 00555 INT32 ExtraBytes, BaseCamelotFilter *pFilter) 00556 00557 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00558 Created: 27/1/97 00559 00560 Inputs: RecordTag - the tag to write this record under 00561 ExtraBytes - The number of extra bytes of information the caller 00562 will write into the record after caling this function 00563 (Space for this many extra bytes will be reserved by 00564 this function when it creates the new file record) 00565 This may be 0 or more bytes. 00566 pFilter - The filter to write to 00567 00568 Returns: NULL if it failed, else a pointer to a record which saves the state 00569 of this valueFunction object. Once the caller has written the record, 00570 they MUST DELETE it. 00571 00572 Purpose: Saves a ValueFunction object to a Xara file. 00573 This function will create a new variable-sized record with the given 00574 record tag, and will write out whatever data is needed to save this 00575 ValueFunction's state to the file. 00576 00577 "ExtraBytes" bytes will be added to the record size to reserve space 00578 at the end of the record for the caller to add their own data. This 00579 is to allow ValueFunctions to be saved embedded in other object's 00580 record structures (e.g. inside different types of attributes). 00581 00582 All ValueFunction record data has 3 sections, whiich are recorded as follows: 00583 1. ValueFunction header, identifying which type of VF is being saved 00584 INT32 ValueFunctionUniqueID (4 bytes) 00585 2. Derived-class-data (0 or more bytes). This particular class adds: 00586 float ConstantValue (4 bytes) 00587 3. Caller data. This is written by the caller to the returned record 00588 object. This data must be ExtraBytes (0 or more) bytes in length. 00589 00590 SeeAlso: ValueFunctionConstant::CreateAndReadFileRecord 00591 00592 ******************************************************************************************/ 00593 00594 CamelotFileRecord *ValueFunctionConstant::WriteFileRecord(INT32 RecordTag, INT32 ExtraBytes, 00595 BaseCamelotFilter *pFilter) 00596 { 00597 ERROR3IF(pFilter == NULL, "Illegal NULL param"); 00598 ERROR3IF(ExtraBytes < 0, "Stupid ExtraBytes request in ValueFunction::WriteFileRecord"); 00599 00600 // Calculate how many bytes of information this VF will write. We do not include 00601 // the header info written by the base class or the ExtraInfo desired by the caller - 00602 // the base class adds all that in for us. 00603 const INT32 MyRecordSize = 4; 00604 00605 // Create an appropriate record, and write our data to it 00606 CamelotFileRecord *pRec = CreateAndWriteFileRecord(RecordTag, MyRecordSize, ExtraBytes, pFilter); 00607 00608 if (pRec != NULL) 00609 { 00610 // Write out our ValueFunction's specific data. If it fails, then we'll return NULL 00611 if (!pRec->WriteFLOAT((float)Value1)) 00612 { 00613 delete pRec; 00614 pRec = NULL; 00615 } 00616 } 00617 00618 return(pRec); 00619 } 00620 00621 00622 00623 /****************************************************************************************** 00624 00625 > virtual ValueFunction *ValueFunctionConstant::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord) 00626 00627 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00628 Created: 27/1/97 00629 00630 Inputs: pInputRecord - The file record to read 00631 00632 Returns: NULL if it failed, else a pointer to new ValueFunction object representing 00633 whatever was saved in that record. 00634 00635 Purpose: Loads a ValueFunction object from a record which was saved into a file 00636 using the WriteFileRecord call. This is called by the base class 00637 loader routine ReadFileRecord, which finds an appropriate instance 00638 of a derived class to call to load the data in question. 00639 00640 This method creates a new instance of this particular ValueFunction class 00641 and then loads whatever information is necessary from the file to 00642 initialise itself properly. The record read-pointer is left pointing 00643 at the end of the ValueFunction-saved data so that the caller can continue 00644 reading their extra bytes of data after loading the ValueFunction. 00645 00646 SeeAlso: ValueFunctionConstant::WriteFileRecord; 00647 ValueFunctionConstant::ReadFileRecord 00648 00649 ******************************************************************************************/ 00650 00651 ValueFunction *ValueFunctionConstant::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord) 00652 { 00653 ERROR3IF(pInputRecord == NULL, "Illegal NULL param"); 00654 00655 float ConstValue = (float)1.0; 00656 pInputRecord->ReadFLOAT(&ConstValue); 00657 00658 return(new ValueFunctionConstant((double) ConstValue)); 00659 } 00660 00661 00662 00663 00664 00665 00666 00667 00668 00670 // ValueFunctionRandom class 00672 00673 /****************************************************************************************** 00674 00675 > ValueFunctionRandom::ValueFunctionRandom(UINT32 Seed, double Min, double Max) 00676 00677 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00678 Created: 30/12/96 00679 00680 Inputs: Seed - The base random-number seed. This is combined with the 00681 position value to generate a "random" number that will 00682 not change for any given position/seed combination. 00683 00684 Min - The minimum value you want returned 00685 Max - The maximum value you want returned 00686 00687 Purpose: Constructor 00688 The Random ValueFunction returns a pseudo-random value between Min & Max 00689 00690 ******************************************************************************************/ 00691 00692 ValueFunctionRandom::ValueFunctionRandom(UINT32 Seed, double Min, double Max) 00693 { 00694 ERROR3IF(Min > Max, "ValueFunctionRandom: Min should be smaller than Max"); 00695 00696 MinValue = Min; 00697 MaxValue = Max; 00698 SeedValue = Seed; 00699 00700 // Fill in the array with random values 00701 srand(SeedValue); 00702 for (INT32 i = 0; i < NumRandomValues; i++) 00703 Array[i] = rand() & 0xffff; 00704 } 00705 00706 00707 00708 /****************************************************************************************** 00709 00710 > virtual double ValueFunctionRandom::GetValue(double Position) 00711 00712 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00713 Created: 30/12/96 00714 00715 Inputs: Position - A value between 0.0 and 1.0 00716 Returns: A "Random" value (based on the Seed, Min, and Max values given to the 00717 constructor) representing the value of the function at the given Position. 00718 00719 Purpose: To read the value of this function at a given position 00720 00721 Notes: Random returns a pseudo-random value based on the position and the 00722 Seed value, and clamped within the range given to the constructor. 00723 If the Seed/Min/Max values are unchanged, the same position will 00724 always return the same value. 00725 00726 ******************************************************************************************/ 00727 00728 double ValueFunctionRandom::GetValue(double Position) 00729 { 00730 // Determine which array entry to use, and how much to linearly interpolate 00731 // between it and the next value 00732 INT32 Index = (INT32) floor(Position * (double)(0x400 * (NumRandomValues - 2))); 00733 double MixFraction = (double)(Index & 0x3ff) / (double)0x3ff; 00734 00735 // Scale the Index value down into the proper range now, and make sure it's safe 00736 Index /= 0x400; 00737 if (Index < 0) 00738 Index = 0; 00739 if (Index > NumRandomValues - 2) 00740 Index = NumRandomValues - 2; 00741 00742 // Get a random number between 0.0 and 1.0 00743 double Value = ((double)Array[Index] * (1.0 - MixFraction)) + ((double)Array[Index+1] * MixFraction); 00744 Value /= (double) 0xffff; 00745 00746 // And scale the result into the range specified by the caller 00747 return( MinValue + (Value * (MaxValue - MinValue)) ); 00748 } 00749 00750 00751 00752 /****************************************************************************************** 00753 00754 > virtual ValueFunction *ValueFunctionRandom::Clone(void) 00755 00756 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00757 Created: 8/1/97 00758 00759 Returns: NULL if it failed, else an exact copy of this object 00760 00761 Purpose: Clone operator. Creates an exact copy of this object 00762 00763 ******************************************************************************************/ 00764 00765 ValueFunction *ValueFunctionRandom::Clone(void) 00766 { 00767 ValueFunction *pClone = new ValueFunctionRandom(SeedValue, MinValue, MaxValue); 00768 return(pClone); 00769 } 00770 00771 00772 00773 /****************************************************************************************** 00774 00775 > virtual BOOL ValueFunctionRandom::IsDifferent(ValueFunction *Other) 00776 00777 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00778 Created: 8/1/97 00779 00780 Inputs: pOther - Another ValueFunction object to compare this one to 00781 00782 Returns: TRUE, always 00783 00784 Purpose: Comparator. 00785 Determines if 2 different ValueFunction objects are considered 00786 different. 00787 00788 ******************************************************************************************/ 00789 00790 BOOL ValueFunctionRandom::IsDifferent(ValueFunction *pOther) 00791 { 00792 return(TRUE); // Random value functions always consider themselves different 00793 } 00794 00795 00796 00797 /****************************************************************************************** 00798 00799 > virtual CamelotFileRecord *ValueFunctionRandom::WriteFileRecord(INT32 RecordTag, 00800 INT32 ExtraBytes, BaseCamelotFilter *pFilter) 00801 00802 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00803 Created: 27/1/97 00804 00805 Inputs: RecordTag - the tag to write this record under 00806 ExtraBytes - The number of extra bytes of information the caller 00807 will write into the record after caling this function 00808 (Space for this many extra bytes will be reserved by 00809 this function when it creates the new file record) 00810 This may be 0 or more bytes. 00811 pFilter - The filter to write to 00812 00813 Returns: NULL if it failed, else a pointer to a record which saves the state 00814 of this valueFunction object. Once the caller has written the record, 00815 they MUST DELETE it. 00816 00817 Purpose: Saves a ValueFunction object to a Xara file. 00818 This function will create a new variable-sized record with the given 00819 record tag, and will write out whatever data is needed to save this 00820 ValueFunction's state to the file. 00821 00822 "ExtraBytes" bytes will be added to the record size to reserve space 00823 at the end of the record for the caller to add their own data. This 00824 is to allow ValueFunctions to be saved embedded in other object's 00825 record structures (e.g. inside different types of attributes). 00826 00827 All ValueFunction record data has 3 sections, whiich are recorded as follows: 00828 1. ValueFunction header, identifying which type of VF is being saved 00829 INT32 ValueFunctionUniqueID (4 bytes) 00830 2. Derived-class-data (0 or more bytes). This particular class adds: 00831 UINT32 SeedValue 00832 float MinValue 00833 float MaxValue (12 bytes) 00834 3. Caller data. This is written by the caller to the returned record 00835 object. This data must be ExtraBytes (0 or more) bytes in length. 00836 00837 SeeAlso: ValueFunctionRandom::CreateAndReadFileRecord 00838 00839 ******************************************************************************************/ 00840 00841 CamelotFileRecord *ValueFunctionRandom::WriteFileRecord(INT32 RecordTag, INT32 ExtraBytes, 00842 BaseCamelotFilter *pFilter) 00843 { 00844 ERROR3IF(pFilter == NULL, "Illegal NULL param"); 00845 ERROR3IF(ExtraBytes < 0, "Stupid ExtraBytes request in ValueFunction::WriteFileRecord"); 00846 00847 // Calculate how many bytes of information this VF will write. We do not include 00848 // the header info written by the base class or the ExtraInfo desired by the caller - 00849 // the base class adds all that in for us. 00850 const INT32 MyRecordSize = 12; 00851 00852 // Create an appropriate record, and write our data to it 00853 CamelotFileRecord *pRec = CreateAndWriteFileRecord(RecordTag, MyRecordSize, ExtraBytes, pFilter); 00854 00855 if (pRec != NULL) 00856 { 00857 // Write out our ValueFunction's specific data. If it fails, then we'll return NULL 00858 BOOL ok = TRUE; 00859 if (ok) ok = pRec->WriteUINT32((UINT32)SeedValue); 00860 if (ok) ok = pRec->WriteFLOAT((float)MinValue); 00861 if (ok) ok = pRec->WriteFLOAT((float)MaxValue); 00862 00863 if (!ok) 00864 { 00865 delete pRec; 00866 pRec = NULL; 00867 } 00868 } 00869 00870 return(pRec); 00871 } 00872 00873 00874 00875 /****************************************************************************************** 00876 00877 > virtual ValueFunction *ValueFunctionRandom::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord) 00878 00879 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00880 Created: 27/1/97 00881 00882 Inputs: pInputRecord - The file record to read 00883 00884 Returns: NULL if it failed, else a pointer to new ValueFunction object representing 00885 whatever was saved in that record. 00886 00887 Purpose: Loads a ValueFunction object from a record which was saved into a file 00888 using the WriteFileRecord call. This is called by the base class 00889 loader routine ReadFileRecord, which finds an appropriate instance 00890 of a derived class to call to load the data in question. 00891 00892 This method creates a new instance of this particular ValueFunction class 00893 and then loads whatever information is necessary from the file to 00894 initialise itself properly. The record read-pointer is left pointing 00895 at the end of the ValueFunction-saved data so that the caller can continue 00896 reading their extra bytes of data after loading the ValueFunction. 00897 00898 SeeAlso: ValueFunctionRandom::WriteFileRecord; 00899 ValueFunctionRandom::ReadFileRecord 00900 00901 ******************************************************************************************/ 00902 00903 ValueFunction *ValueFunctionRandom::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord) 00904 { 00905 ERROR3IF(pInputRecord == NULL, "Illegal NULL param"); 00906 00907 UINT32 SeedValue = 1; 00908 float MinValue = (float) 0.0; 00909 float MaxValue = (float) 0.0; 00910 00911 pInputRecord->ReadUINT32(&SeedValue); 00912 pInputRecord->ReadFLOAT(&MinValue); 00913 pInputRecord->ReadFLOAT(&MaxValue); 00914 00915 return(new ValueFunctionRandom((UINT32) SeedValue, (double) MinValue, (double) MinValue)); 00916 } 00917 00918 00919 00920 00921 00922 00923 00925 // ValueFunctionRamp classes 00927 00928 00929 /****************************************************************************************** 00930 00931 > ValueFunctionRamp::ValueFunctionRamp(double StartValue, double EndValue) 00932 00933 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00934 Created: 30/12/96 00935 00936 Inputs: StartValue - The value to be used at the 0.0 position 00937 EndValue - The value to be used at the 1.0 position 00938 00939 Purpose: Constructor 00940 Ramp functions interpolate between two values in some fashion 00941 Derived classes provide such things as linear and sine-wave interpolations 00942 00943 ******************************************************************************************/ 00944 00945 ValueFunctionRamp::ValueFunctionRamp(double StartValue, double EndValue) 00946 { 00947 Value1 = StartValue; 00948 Value2 = EndValue; 00949 } 00950 00951 00952 00953 /****************************************************************************************** 00954 00955 > virtual BOOL ValueFunctionRamp::IsDifferent(ValueFunction *Other) 00956 00957 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00958 Created: 8/1/97 00959 00960 Inputs: pOther - Another ValueFunction object to compare this one to 00961 00962 Returns: TRUE if the objects are considered different, 00963 FALSE if they are considered identical 00964 00965 Purpose: Comparator. 00966 Determines if 2 different ValueFunction objects are considered 00967 different. 00968 00969 Notes: Calls the base class to see if they are different classes, 00970 and then compares identical classes by checking member vars 00971 00972 ******************************************************************************************/ 00973 00974 BOOL ValueFunctionRamp::IsDifferent(ValueFunction *pOther) 00975 { 00976 if (ValueFunction::IsDifferent(pOther)) 00977 return(TRUE); 00978 00979 // Both objects are instances of this class, so compare them more carefully 00980 return( (Value1 != ((ValueFunctionRamp *)pOther)->Value1) || 00981 (Value2 != ((ValueFunctionRamp *)pOther)->Value2) ); 00982 } 00983 00984 00985 00986 /****************************************************************************************** 00987 00988 > virtual CamelotFileRecord *ValueFunctionRamp::WriteFileRecord(INT32 RecordTag, 00989 INT32 ExtraBytes, BaseCamelotFilter *pFilter) 00990 00991 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00992 Created: 27/1/97 00993 00994 Inputs: RecordTag - the tag to write this record under 00995 ExtraBytes - The number of extra bytes of information the caller 00996 will write into the record after caling this function 00997 (Space for this many extra bytes will be reserved by 00998 this function when it creates the new file record) 00999 This may be 0 or more bytes. 01000 pFilter - The filter to write to 01001 01002 Returns: NULL if it failed, else a pointer to a record which saves the state 01003 of this valueFunction object. Once the caller has written the record, 01004 they MUST DELETE it. 01005 01006 Purpose: Saves a ValueFunction object to a Xara file. 01007 This function will create a new variable-sized record with the given 01008 record tag, and will write out whatever data is needed to save this 01009 ValueFunction's state to the file. 01010 01011 "ExtraBytes" bytes will be added to the record size to reserve space 01012 at the end of the record for the caller to add their own data. This 01013 is to allow ValueFunctions to be saved embedded in other object's 01014 record structures (e.g. inside different types of attributes). 01015 01016 All ValueFunction record data has 3 sections, whiich are recorded as follows: 01017 1. ValueFunction header, identifying which type of VF is being saved 01018 INT32 ValueFunctionUniqueID (4 bytes) 01019 2. Derived-class-data (0 or more bytes). This particular class adds: 01020 float Value1 01021 float Value2 (8 bytes) 01022 3. Caller data. This is written by the caller to the returned record 01023 object. This data must be ExtraBytes (0 or more) bytes in length. 01024 01025 ******************************************************************************************/ 01026 01027 CamelotFileRecord *ValueFunctionRamp::WriteFileRecord(INT32 RecordTag, INT32 ExtraBytes, 01028 BaseCamelotFilter *pFilter) 01029 { 01030 ERROR3IF(pFilter == NULL, "Illegal NULL param"); 01031 ERROR3IF(ExtraBytes < 0, "Stupid ExtraBytes request in ValueFunction::WriteFileRecord"); 01032 01033 // Calculate how many bytes of information this VF will write. We do not include 01034 // the header info written by the base class or the ExtraInfo desired by the caller - 01035 // the base class adds all that in for us. 01036 const INT32 MyRecordSize = 8; 01037 01038 // Create an appropriate record, and write our data to it 01039 CamelotFileRecord *pRec = CreateAndWriteFileRecord(RecordTag, MyRecordSize, ExtraBytes, pFilter); 01040 01041 if (pRec != NULL) 01042 { 01043 BOOL ok = TRUE; 01044 if (ok) ok = pRec->WriteFLOAT((FLOAT) Value1); 01045 if (ok) ok = pRec->WriteFLOAT((FLOAT) Value2); 01046 01047 if (!ok) // If we failed, clean up & return NULL 01048 { 01049 delete pRec; 01050 pRec = NULL; 01051 } 01052 } 01053 01054 return(pRec); 01055 } 01056 01057 01058 01059 01060 01061 01062 /****************************************************************************************** 01063 01064 > virtual double ValueFunctionRampLinear::GetValue(double Position) 01065 01066 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 01067 Created: 30/12/96 01068 01069 Inputs: Position - A value between 0.0 and 1.0 01070 Returns: A value (between Value1 and Value2 given in the constructor) representing 01071 the value of the function at the given Position. 01072 01073 Purpose: To read the value of this function at a given position 01074 01075 Notes: RampLinear is a linear interpolation between the start & end values 01076 01077 ******************************************************************************************/ 01078 01079 double ValueFunctionRampLinear::GetValue(double Position) 01080 { 01081 return(((1.0 - Position) * Value1) + (Position * Value2)); 01082 } 01083 01084 01085 01086 /****************************************************************************************** 01087 01088 > virtual ValueFunction *ValueFunctionRampLinear::Clone(void) 01089 01090 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 01091 Created: 8/1/97 01092 01093 Returns: NULL if it failed, else an exact copy of this object 01094 01095 Purpose: Clone operator. Creates an exact copy of this object 01096 01097 ******************************************************************************************/ 01098 01099 ValueFunction *ValueFunctionRampLinear::Clone(void) 01100 { 01101 ValueFunction *pClone = new ValueFunctionRampLinear(Value1, Value2); 01102 return(pClone); 01103 } 01104 01105 01106 01107 /****************************************************************************************** 01108 01109 > virtual ValueFunction *ValueFunctionRampLinear::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord) 01110 01111 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 01112 Created: 27/1/97 01113 01114 Inputs: pInputRecord - The file record to read 01115 01116 Returns: NULL if it failed, else a pointer to new ValueFunction object representing 01117 whatever was saved in that record. 01118 01119 Purpose: Loads a ValueFunction object from a record which was saved into a file 01120 using the WriteFileRecord call. This is called by the base class 01121 loader routine ReadFileRecord, which finds an appropriate instance 01122 of a derived class to call to load the data in question. 01123 01124 This method creates a new instance of this particular ValueFunction class 01125 and then loads whatever information is necessary from the file to 01126 initialise itself properly. The record read-pointer is left pointing 01127 at the end of the ValueFunction-saved data so that the caller can continue 01128 reading their extra bytes of data after loading the ValueFunction. 01129 01130 SeeAlso: ValueFunctionRamp::WriteFileRecord 01131 01132 ******************************************************************************************/ 01133 01134 ValueFunction *ValueFunctionRampLinear::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord) 01135 { 01136 ERROR3IF(pInputRecord == NULL, "Illegal NULL param"); 01137 01138 float Value1 = (float) 1.0; 01139 float Value2 = (float) 0.0; 01140 01141 pInputRecord->ReadFLOAT(&Value1); 01142 pInputRecord->ReadFLOAT(&Value2); 01143 01144 return(new ValueFunctionRampLinear((double) Value1, (double) Value2)); 01145 } 01146 01147 01148 01149 01150 01151 /****************************************************************************************** 01152 01153 > virtual double ValueFunctionRampS::GetValue(double Position) 01154 01155 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 01156 Created: 30/12/96 01157 01158 Inputs: Position - A value between 0.0 and 1.0 01159 Returns: A value (between Value1 and Value2 given in the constructor) representing 01160 the value of the function at the given Position. 01161 01162 Purpose: To read the value of this function at a given position 01163 01164 Notes: RampS is a half sine-wave "S" shaped function 01165 01166 ******************************************************************************************/ 01167 01168 double ValueFunctionRampS::GetValue(double Position) 01169 { 01170 const double MixValue = (cos(Position * Pi) + 1.0) / 2.0; 01171 01172 return((MixValue * Value1) + ((1.0 - MixValue) * Value2)); 01173 } 01174 01175 01176 /****************************************************************************************** 01177 01178 > virtual INT32 ValueFunctionRampS::GetMinimumRecursionDepth(void) 01179 01180 Author: Priestley (Xara Group Ltd) <camelotdev@xara.com> 01181 Created: 9/10/2000 01182 01183 Purpose: Overriden function to indicate to the path stroker how many recursions to 01184 perform at minimum before declaring a line segment 'flat' enough 01185 01186 ******************************************************************************************/ 01187 01188 INT32 ValueFunctionRampS::GetMinimumRecursionDepth() 01189 { 01190 return 2; 01191 } 01192 01193 01194 /****************************************************************************************** 01195 01196 > virtual ValueFunction *ValueFunctionRampS::Clone(void) 01197 01198 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 01199 Created: 8/1/97 01200 01201 Returns: NULL if it failed, else an exact copy of this object 01202 01203 Purpose: Clone operator. Creates an exact copy of this object 01204 01205 ******************************************************************************************/ 01206 01207 ValueFunction *ValueFunctionRampS::Clone(void) 01208 { 01209 ValueFunction *pClone = new ValueFunctionRampS(Value1, Value2); 01210 return(pClone); 01211 } 01212 01213 01214 01215 /****************************************************************************************** 01216 01217 > virtual ValueFunction *ValueFunctionRampS::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord) 01218 01219 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 01220 Created: 27/1/97 01221 01222 Inputs: pInputRecord - The file record to read 01223 01224 Returns: NULL if it failed, else a pointer to new ValueFunction object representing 01225 whatever was saved in that record. 01226 01227 Purpose: Loads a ValueFunction object from a record which was saved into a file 01228 using the WriteFileRecord call. This is called by the base class 01229 loader routine ReadFileRecord, which finds an appropriate instance 01230 of a derived class to call to load the data in question. 01231 01232 This method creates a new instance of this particular ValueFunction class 01233 and then loads whatever information is necessary from the file to 01234 initialise itself properly. The record read-pointer is left pointing 01235 at the end of the ValueFunction-saved data so that the caller can continue 01236 reading their extra bytes of data after loading the ValueFunction. 01237 01238 SeeAlso: ValueFunctionRamp::WriteFileRecord 01239 01240 ******************************************************************************************/ 01241 01242 ValueFunction *ValueFunctionRampS::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord) 01243 { 01244 ERROR3IF(pInputRecord == NULL, "Illegal NULL param"); 01245 01246 float Value1 = (float) 1.0; 01247 float Value2 = (float) 0.0; 01248 01249 pInputRecord->ReadFLOAT(&Value1); 01250 pInputRecord->ReadFLOAT(&Value2); 01251 01252 return(new ValueFunctionRampS((double) Value1, (double) Value2)); 01253 } 01254 01255 01256 01257 /****************************************************************************************** 01258 01259 > virtual double ValueFunctionRampS2::GetValue(double Position) 01260 01261 Author: Priestley (Xara Group Ltd) <camelotdev@xara.com> from Jason 01262 Created: 9/10/2000 01263 01264 Inputs: Position - A value between 0.0 and 1.0 01265 Returns: A value (between Value1 and Value2 given in the constructor) representing 01266 the value of the function at the given Position. 01267 01268 Purpose: To read the value of this function at a given position 01269 01270 Notes: RampS2 is a half sine-wave "S" shaped function - Value2 set to none-zero 01271 01272 ******************************************************************************************/ 01273 01274 double ValueFunctionRampS2::GetValue(double Position) 01275 { 01276 const double MixValue = (cos(Position * Pi) + 1.0) / 2.0; 01277 01278 return((MixValue * Value1) + ((1.0 - MixValue) * Value2)); 01279 } 01280 01281 01282 01283 /****************************************************************************************** 01284 01285 > virtual ValueFunction *ValueFunctionRampS2::Clone(void) 01286 01287 Author: Priestley (Xara Group Ltd) <camelotdev@xara.com> from Jason 01288 Created: 9/10/2000 01289 01290 Returns: NULL if it failed, else an exact copy of this object 01291 01292 Purpose: Clone operator. Creates an exact copy of this object 01293 01294 ******************************************************************************************/ 01295 01296 ValueFunction *ValueFunctionRampS2::Clone(void) 01297 { 01298 ValueFunction *pClone = new ValueFunctionRampS2(Value1, Value2); 01299 return(pClone); 01300 } 01301 01302 01303 01304 /****************************************************************************************** 01305 01306 > virtual ValueFunction *ValueFunctionRampS2::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord) 01307 01308 Author: Priestley (Xara Group Ltd) <camelotdev@xara.com> from Jason 01309 Created: 9/10/2000 01310 01311 Inputs: pInputRecord - The file record to read 01312 01313 Returns: NULL if it failed, else a pointer to new ValueFunction object representing 01314 whatever was saved in that record. 01315 01316 Purpose: Loads a ValueFunction object from a record which was saved into a file 01317 using the WriteFileRecord call. This is called by the base class 01318 loader routine ReadFileRecord, which finds an appropriate instance 01319 of a derived class to call to load the data in question. 01320 01321 This method creates a new instance of this particular ValueFunction class 01322 and then loads whatever information is necessary from the file to 01323 initialise itself properly. The record read-pointer is left pointing 01324 at the end of the ValueFunction-saved data so that the caller can continue 01325 reading their extra bytes of data after loading the ValueFunction. 01326 01327 SeeAlso: ValueFunctionRamp::WriteFileRecord 01328 01329 ******************************************************************************************/ 01330 01331 ValueFunction *ValueFunctionRampS2::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord) 01332 { 01333 ERROR3IF(pInputRecord == NULL, "Illegal NULL param"); 01334 01335 float Value1 = (float) 1.0; 01336 float Value2 = (float) 0.2; 01337 01338 pInputRecord->ReadFLOAT(&Value1); 01339 pInputRecord->ReadFLOAT(&Value2); 01340 01341 return(new ValueFunctionRampS2((double) Value1, (double) Value2)); 01342 } 01343 01344 /****************************************************************************************** 01345 01346 > virtual INT32 ValueFunctionRampS2::GetMinimumRecursionDepth(void) 01347 01348 Author: Priestley (Xara Group Ltd) <camelotdev@xara.com> 01349 Created: 9/10/2000 01350 01351 Purpose: Overriden function to indicate to the path stroker how many recursions to 01352 perform at minimum before declaring a line segment 'flat' enough 01353 01354 ******************************************************************************************/ 01355 01356 INT32 ValueFunctionRampS2::GetMinimumRecursionDepth() 01357 { 01358 return 2; 01359 } 01360 01361 01362 01363 01364 01365 /****************************************************************************************** 01366 01367 > virtual double ValueFunctionRampL::GetValue(double Position) 01368 01369 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 01370 Created: 28/2/97 01371 01372 Inputs: Position - A value between 0.0 and 1.0 01373 Returns: A value (between Value1 and Value2 given in the constructor) representing 01374 the value of the function at the given Position. 01375 01376 Purpose: To read the value of this function at a given position 01377 01378 Notes: RampL is a half sine-wave "S" shaped function 01379 01380 ******************************************************************************************/ 01381 01382 double ValueFunctionRampL::GetValue(double Position) 01383 { 01384 const double MixValue = cos((Pi/2.0) + (Position * Pi/2.0)) + 1.0; 01385 01386 return((MixValue * Value1) + ((1.0 - MixValue) * Value2)); 01387 } 01388 01389 01390 /****************************************************************************************** 01391 01392 > virtual INT32 ValueFunctionRampL::GetMinimumRecursionDepth(void) 01393 01394 Author: Priestley (Xara Group Ltd) <camelotdev@xara.com> 01395 Created: 9/10/2000 01396 01397 Purpose: Overriden function to indicate to the path stroker how many recursions to 01398 perform at minimum before declaring a line segment 'flat' enough 01399 01400 ******************************************************************************************/ 01401 01402 INT32 ValueFunctionRampL::GetMinimumRecursionDepth() 01403 { 01404 return 2; 01405 } 01406 01407 01408 /****************************************************************************************** 01409 01410 > virtual ValueFunction *ValueFunctionRampL::Clone(void) 01411 01412 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 01413 Created: 28/2/97 01414 01415 Returns: NULL if it failed, else an exact copy of this object 01416 01417 Purpose: Clone operator. Creates an exact copy of this object 01418 01419 ******************************************************************************************/ 01420 01421 ValueFunction *ValueFunctionRampL::Clone(void) 01422 { 01423 ValueFunction *pClone = new ValueFunctionRampL(Value1, Value2); 01424 return(pClone); 01425 } 01426 01427 01428 01429 /****************************************************************************************** 01430 01431 > virtual ValueFunction *ValueFunctionRampL::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord) 01432 01433 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 01434 Created: 28/2/97 01435 01436 Inputs: pInputRecord - The file record to read 01437 01438 Returns: NULL if it failed, else a pointer to new ValueFunction object representing 01439 whatever was saved in that record. 01440 01441 Purpose: Loads a ValueFunction object from a record which was saved into a file 01442 using the WriteFileRecord call. This is called by the base class 01443 loader routine ReadFileRecord, which finds an appropriate instance 01444 of a derived class to call to load the data in question. 01445 01446 This method creates a new instance of this particular ValueFunction class 01447 and then loads whatever information is necessary from the file to 01448 initialise itself properly. The record read-pointer is left pointing 01449 at the end of the ValueFunction-saved data so that the caller can continue 01450 reading their extra bytes of data after loading the ValueFunction. 01451 01452 SeeAlso: ValueFunctionRamp::WriteFileRecord 01453 01454 ******************************************************************************************/ 01455 01456 ValueFunction *ValueFunctionRampL::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord) 01457 { 01458 ERROR3IF(pInputRecord == NULL, "Illegal NULL param"); 01459 01460 float Value1 = (float) 1.0; 01461 float Value2 = (float) 0.0; 01462 01463 pInputRecord->ReadFLOAT(&Value1); 01464 pInputRecord->ReadFLOAT(&Value2); 01465 01466 return(new ValueFunctionRampL((double) Value1, (double) Value2)); 01467 } 01468 01469 01470 /****************************************************************************************** 01471 01472 > virtual double ValueFunctionRampL2::GetValue(double Position) 01473 01474 Author: Priestley (Xara Group Ltd) <camelotdev@xara.com> from Jason 01475 Created: 9/10/2000 01476 01477 Inputs: Position - A value between 0.0 and 1.0 01478 Returns: A value (between Value1 and Value2 given in the constructor) representing 01479 the value of the function at the given Position. 01480 01481 Purpose: To read the value of this function at a given position 01482 01483 Notes: RampL is a half sine-wave "S" shaped function 01484 01485 ******************************************************************************************/ 01486 01487 double ValueFunctionRampL2::GetValue(double Position) 01488 { 01489 const double MixValue = cos((Pi/2.0) + (Position * Pi/2.0)) + 1.0; 01490 01491 return((MixValue * Value1) + ((1.0 - MixValue) * Value2)); 01492 } 01493 01494 01495 /****************************************************************************************** 01496 01497 > virtual INT32 ValueFunctionRampL2::GetMinimumRecursionDepth(void) 01498 01499 Author: Priestley (Xara Group Ltd) <camelotdev@xara.com> 01500 Created: 9/10/2000 01501 01502 Purpose: Overriden function to indicate to the path stroker how many recursions to 01503 perform at minimum before declaring a line segment 'flat' enough 01504 01505 ******************************************************************************************/ 01506 01507 INT32 ValueFunctionRampL2::GetMinimumRecursionDepth() 01508 { 01509 return 2; 01510 } 01511 01512 01513 /****************************************************************************************** 01514 01515 > virtual ValueFunction *ValueFunctionRampL::Clone(void) 01516 01517 Author: Priestley (Xara Group Ltd) <camelotdev@xara.com> from Jason 01518 Created: 9/10/2000 01519 01520 Returns: NULL if it failed, else an exact copy of this object 01521 01522 Purpose: Clone operator. Creates an exact copy of this object 01523 01524 ******************************************************************************************/ 01525 01526 ValueFunction *ValueFunctionRampL2::Clone(void) 01527 { 01528 ValueFunction *pClone = new ValueFunctionRampL2(Value1, Value2); 01529 return(pClone); 01530 } 01531 01532 01533 01534 /****************************************************************************************** 01535 01536 > virtual ValueFunction *ValueFunctionRampL::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord) 01537 01538 Author: Priestley (Xara Group Ltd) <camelotdev@xara.com> from Jason 01539 Created: 9/10/2000 01540 01541 Inputs: pInputRecord - The file record to read 01542 01543 Returns: NULL if it failed, else a pointer to new ValueFunction object representing 01544 whatever was saved in that record. 01545 01546 Purpose: Loads a ValueFunction object from a record which was saved into a file 01547 using the WriteFileRecord call. This is called by the base class 01548 loader routine ReadFileRecord, which finds an appropriate instance 01549 of a derived class to call to load the data in question. 01550 01551 This method creates a new instance of this particular ValueFunction class 01552 and then loads whatever information is necessary from the file to 01553 initialise itself properly. The record read-pointer is left pointing 01554 at the end of the ValueFunction-saved data so that the caller can continue 01555 reading their extra bytes of data after loading the ValueFunction. 01556 01557 SeeAlso: ValueFunctionRamp::WriteFileRecord 01558 01559 ******************************************************************************************/ 01560 01561 ValueFunction *ValueFunctionRampL2::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord) 01562 { 01563 ERROR3IF(pInputRecord == NULL, "Illegal NULL param"); 01564 01565 float Value1 = (float) 1.0; 01566 float Value2 = (float) 0.2; 01567 01568 pInputRecord->ReadFLOAT(&Value1); 01569 pInputRecord->ReadFLOAT(&Value2); 01570 01571 return(new ValueFunctionRampL2((double) Value1, (double) Value2)); 01572 } 01573 01574 01575 01576 /****************************************************************************************** 01577 01578 > virtual double ValueFunctionSawTooth::GetValue(double Position) 01579 01580 Author: Priestley (Xara Group Ltd) <camelotdev@xara.com> 01581 Created: 9/10/2000 01582 01583 Inputs: Position - A value between 0.0 and 1.0 01584 Returns: A value (between Value1 and Value2 given in the constructor) representing 01585 the value of the function at the given Position. 01586 01587 Purpose: To read the value of this function at a given position 01588 01589 Notes: SawTooth is a half sine-wave "S" shaped function 01590 01591 ******************************************************************************************/ 01592 01593 double ValueFunctionSawTooth::GetValue(double Position) 01594 { 01595 if (Position == 1.0) 01596 { 01597 return 0.0; 01598 } 01599 else 01600 { 01601 double Value = (9.0 * Position) - (floor(9.0 * Position)); 01602 return(1.0 - (Value * Value)); 01603 } 01604 } 01605 01606 01607 01608 /****************************************************************************************** 01609 01610 > virtual ValueFunction *ValueFunctionSawTooth::Clone(void) 01611 01612 Author: Priestley (Xara Group Ltd) <camelotdev@xara.com> from Jason 01613 Created: 9/10/2000 01614 01615 Returns: NULL if it failed, else an exact copy of this object 01616 01617 Purpose: Clone operator. Creates an exact copy of this object 01618 01619 ******************************************************************************************/ 01620 01621 ValueFunction *ValueFunctionSawTooth::Clone(void) 01622 { 01623 ValueFunction *pClone = new ValueFunctionSawTooth(Value1, Value2); 01624 return(pClone); 01625 } 01626 01627 01628 01629 /****************************************************************************************** 01630 01631 > virtual INT32 ValueFunctionSawTooth::GetMinimumRecursionDepth(void) 01632 01633 Author: Priestley (Xara Group Ltd) <camelotdev@xara.com> 01634 Created: 9/10/2000 01635 01636 Purpose: Overriden function to indicate to the path stroker how many recursions to 01637 perform at minimum before declaring a line segment 'flat' enough 01638 01639 ******************************************************************************************/ 01640 01641 INT32 ValueFunctionSawTooth::GetMinimumRecursionDepth() 01642 { 01643 return 4; 01644 } 01645 01646 01647 01648 /****************************************************************************************** 01649 01650 > virtual ValueFunction *ValueFunctionSawTooth::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord) 01651 01652 Author: Priestley (Xara Group Ltd) <camelotdev@xara.com> from Jason 01653 Created: 9/10/2000 01654 01655 Inputs: pInputRecord - The file record to read 01656 01657 Returns: NULL if it failed, else a pointer to new ValueFunction object representing 01658 whatever was saved in that record. 01659 01660 Purpose: Loads a ValueFunction object from a record which was saved into a file 01661 using the WriteFileRecord call. This is called by the base class 01662 loader routine ReadFileRecord, which finds an appropriate instance 01663 of a derived class to call to load the data in question. 01664 01665 This method creates a new instance of this particular ValueFunction class 01666 and then loads whatever information is necessary from the file to 01667 initialise itself properly. The record read-pointer is left pointing 01668 at the end of the ValueFunction-saved data so that the caller can continue 01669 reading their extra bytes of data after loading the ValueFunction. 01670 01671 SeeAlso: ValueFunctionRamp::WriteFileRecord 01672 01673 ******************************************************************************************/ 01674 01675 ValueFunction *ValueFunctionSawTooth::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord) 01676 { 01677 ERROR3IF(pInputRecord == NULL, "Illegal NULL param"); 01678 01679 float Value1 = (float) 1.0; 01680 float Value2 = (float) 0.0; 01681 01682 pInputRecord->ReadFLOAT(&Value1); 01683 pInputRecord->ReadFLOAT(&Value2); 01684 01685 return(new ValueFunctionSawTooth((double) Value1, (double) Value2)); 01686 } 01687 01688 01689 01690 /****************************************************************************************** 01691 01692 > virtual double ValueFunctionCurvedSawTooth::GetValue(double Position) 01693 01694 Author: Priestley (Xara Group Ltd) <camelotdev@xara.com> 01695 Created: 9/10/2000 01696 01697 Inputs: Position - A value between 0.0 and 1.0 01698 Returns: A value (between Value1 and Value2 given in the constructor) representing 01699 the value of the function at the given Position. 01700 01701 Purpose: To read the value of this function at a given position 01702 01703 Notes: CurvedSawTooth is a half sine-wave "S" shaped function 01704 01705 ******************************************************************************************/ 01706 01707 double ValueFunctionPropeller::GetValue(double Position) 01708 { 01709 double Value; 01710 01711 if (Position < 0.15) 01712 { 01713 //Draw a curved beginning bit... 01714 Position = 1.0 - Position/0.15; 01715 if ( Position>1.0 ) 01716 Position = 1.0; 01717 Value = sqrt(1-Position*Position); 01718 } 01719 else 01720 { 01721 if (Position > 0.85) 01722 { 01723 //Draw a curved end bit... 01724 Position = (Position - 0.85) / 0.15; 01725 if ( Position>1.0 ) 01726 Position = 1.0; 01727 Value = sqrt(1-Position*Position); 01728 } 01729 else 01730 { 01731 //Scale Position to be a value between 0 and 1 based on how far through between 01732 //0.15 and 0.85 it is... 01733 Position = (Position - 0.15) / 0.7; 01734 Value = (cos(Position * 2.0 * Pi) + 1.5) * 0.4; 01735 } 01736 } 01737 return Value; 01738 } 01739 01740 01741 /****************************************************************************************** 01742 01743 > virtual INT32 ValueFunctionPropeller::GetMinimumRecursionDepth(void) 01744 01745 Author: Priestley (Xara Group Ltd) <camelotdev@xara.com> 01746 Created: 9/10/2000 01747 01748 Purpose: Overriden function to indicate to the path stroker how many recursions to 01749 perform at minimum before declaring a line segment 'flat' enough 01750 01751 ******************************************************************************************/ 01752 01753 INT32 ValueFunctionPropeller::GetMinimumRecursionDepth() 01754 { 01755 return 4; 01756 } 01757 01758 01759 /****************************************************************************************** 01760 01761 > virtual ValueFunction *ValueFunctionPropeller::Clone(void) 01762 01763 Author: Priestley (Xara Group Ltd) <camelotdev@xara.com> from Jason 01764 Created: 9/10/2000 01765 01766 Returns: NULL if it failed, else an exact copy of this object 01767 01768 Purpose: Clone operator. Creates an exact copy of this object 01769 01770 ******************************************************************************************/ 01771 01772 ValueFunction *ValueFunctionPropeller::Clone(void) 01773 { 01774 ValueFunction *pClone = new ValueFunctionPropeller(Value1, Value2); 01775 return(pClone); 01776 } 01777 01778 01779 01780 /****************************************************************************************** 01781 01782 > virtual ValueFunction *ValueFunctionPropeller::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord) 01783 01784 Author: Priestley (Xara Group Ltd) <camelotdev@xara.com> from Jason 01785 Created: 9/10/2000 01786 01787 Inputs: pInputRecord - The file record to read 01788 01789 Returns: NULL if it failed, else a pointer to new ValueFunction object representing 01790 whatever was saved in that record. 01791 01792 Purpose: Loads a ValueFunction object from a record which was saved into a file 01793 using the WriteFileRecord call. This is called by the base class 01794 loader routine ReadFileRecord, which finds an appropriate instance 01795 of a derived class to call to load the data in question. 01796 01797 This method creates a new instance of this particular ValueFunction class 01798 and then loads whatever information is necessary from the file to 01799 initialise itself properly. The record read-pointer is left pointing 01800 at the end of the ValueFunction-saved data so that the caller can continue 01801 reading their extra bytes of data after loading the ValueFunction. 01802 01803 SeeAlso: ValueFunctionRamp::WriteFileRecord 01804 01805 ******************************************************************************************/ 01806 01807 ValueFunction *ValueFunctionPropeller::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord) 01808 { 01809 ERROR3IF(pInputRecord == NULL, "Illegal NULL param"); 01810 01811 float Value1 = (float) 1.0; 01812 float Value2 = (float) 0.0; 01813 01814 pInputRecord->ReadFLOAT(&Value1); 01815 pInputRecord->ReadFLOAT(&Value2); 01816 01817 return(new ValueFunctionPropeller((double) Value1, (double) Value2)); 01818 } 01819 01820 /****************************************************************************************** 01821 01822 > virtual double ValueFunctionDoubleRampS::GetValue(double Position) 01823 01824 Author: Priestley (Xara Group Ltd) <camelotdev@xara.com> from Jason 01825 Created: 9/10/2000 01826 01827 Inputs: Position - A value between 0.0 and 1.0 01828 Returns: A value (between Value1 and Value2 given in the constructor) representing 01829 the value of the function at the given Position. 01830 01831 Purpose: To read the value of this function at a given position 01832 01833 Notes: DoubleRampS is a half sine-wave "S" shaped function 01834 01835 ******************************************************************************************/ 01836 01837 double ValueFunctionDoubleRampS::GetValue(double Position) 01838 { 01839 const double MixValue = (cos(Position * 2.0 * Pi) + 1.5) * 0.4; 01840 01841 return((MixValue * Value1) + ((1.0 - MixValue) * Value2)); 01842 } 01843 01844 01845 /****************************************************************************************** 01846 01847 > virtual INT32 ValueFunctionDoubleRampS::GetMinimumRecursionDepth(void) 01848 01849 Author: Priestley (Xara Group Ltd) <camelotdev@xara.com> 01850 Created: 9/10/2000 01851 01852 Purpose: Overriden function to indicate to the path stroker how many recursions to 01853 perform at minimum before declaring a line segment 'flat' enough 01854 01855 ******************************************************************************************/ 01856 01857 INT32 ValueFunctionDoubleRampS::GetMinimumRecursionDepth() 01858 { 01859 return 2; 01860 } 01861 01862 01863 /****************************************************************************************** 01864 01865 > virtual ValueFunction *ValueFunctionDoubleRampS::Clone(void) 01866 01867 Author: Priestley (Xara Group Ltd) <camelotdev@xara.com> from Jason 01868 Created: 9/10/2000 01869 01870 Returns: NULL if it failed, else an exact copy of this object 01871 01872 Purpose: Clone operator. Creates an exact copy of this object 01873 01874 ******************************************************************************************/ 01875 01876 ValueFunction *ValueFunctionDoubleRampS::Clone(void) 01877 { 01878 ValueFunction *pClone = new ValueFunctionDoubleRampS(Value1, Value2); 01879 return(pClone); 01880 } 01881 01882 01883 01884 /****************************************************************************************** 01885 01886 > virtual ValueFunction *ValueFunctionDoubleRampS::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord) 01887 01888 Author: Priestley (Xara Group Ltd) <camelotdev@xara.com> from Jason 01889 Created: 9/10/2000 01890 01891 Inputs: pInputRecord - The file record to read 01892 01893 Returns: NULL if it failed, else a pointer to new ValueFunction object representing 01894 whatever was saved in that record. 01895 01896 Purpose: Loads a ValueFunction object from a record which was saved into a file 01897 using the WriteFileRecord call. This is called by the base class 01898 loader routine ReadFileRecord, which finds an appropriate instance 01899 of a derived class to call to load the data in question. 01900 01901 This method creates a new instance of this particular ValueFunction class 01902 and then loads whatever information is necessary from the file to 01903 initialise itself properly. The record read-pointer is left pointing 01904 at the end of the ValueFunction-saved data so that the caller can continue 01905 reading their extra bytes of data after loading the ValueFunction. 01906 01907 SeeAlso: ValueFunctionRamp::WriteFileRecord 01908 01909 ******************************************************************************************/ 01910 01911 ValueFunction *ValueFunctionDoubleRampS::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord) 01912 { 01913 ERROR3IF(pInputRecord == NULL, "Illegal NULL param"); 01914 01915 float Value1 = (float) 1.0; 01916 float Value2 = (float) 0.0; 01917 01918 pInputRecord->ReadFLOAT(&Value1); 01919 pInputRecord->ReadFLOAT(&Value2); 01920 01921 return(new ValueFunctionDoubleRampS((double) Value1, (double) Value2)); 01922 } 01923 01924 /****************************************************************************************** 01925 01926 > virtual double ValueFunctionIntestine::GetValue(double Position) 01927 01928 Author: Priestley (Xara Group Ltd) <camelotdev@xara.com> from Jason 01929 Created: 9/10/2000 01930 01931 Inputs: Position - A value between 0.0 and 1.0 01932 Returns: A value (between Value1 and Value2 given in the constructor) representing 01933 the value of the function at the given Position. 01934 01935 Purpose: To read the value of this function at a given position 01936 01937 ******************************************************************************************/ 01938 01939 double ValueFunctionIntestine::GetValue(double Position) 01940 { 01941 const double MixValue = ((cos(Position * 20.0 * Pi) + 3.0) / 4.0); 01942 return((MixValue * Value1) + ((1.0 - MixValue) * Value2)); 01943 } 01944 01945 01946 01947 /****************************************************************************************** 01948 01949 > virtual ValueFunction *ValueFunctionIntestine::Clone(void) 01950 01951 Author: Priestley (Xara Group Ltd) <camelotdev@xara.com> from Jason 01952 Created: 9/10/2000 01953 01954 Returns: NULL if it failed, else an exact copy of this object 01955 01956 Purpose: Clone operator. Creates an exact copy of this object 01957 01958 ******************************************************************************************/ 01959 01960 ValueFunction *ValueFunctionIntestine::Clone(void) 01961 { 01962 ValueFunction *pClone = new ValueFunctionIntestine(Value1, Value2); 01963 return(pClone); 01964 } 01965 01966 01967 /****************************************************************************************** 01968 01969 > virtual INT32 ValueFunctionIntestine::GetMinimumRecursionDepth(void) 01970 01971 Author: Priestley (Xara Group Ltd) <camelotdev@xara.com> 01972 Created: 9/10/2000 01973 01974 Purpose: Overriden function to indicate to the path stroker how many recursions to 01975 perform at minimum before declaring a line segment 'flat' enough 01976 01977 ******************************************************************************************/ 01978 01979 INT32 ValueFunctionIntestine::GetMinimumRecursionDepth() 01980 { 01981 return 4; 01982 } 01983 01984 01985 /****************************************************************************************** 01986 01987 > virtual ValueFunction *ValueFunctionIntestine::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord) 01988 01989 Author: Priestley (Xara Group Ltd) <camelotdev@xara.com> from Jason 01990 Created: 9/10/2000 01991 01992 Inputs: pInputRecord - The file record to read 01993 01994 Returns: NULL if it failed, else a pointer to new ValueFunction object representing 01995 whatever was saved in that record. 01996 01997 Purpose: Loads a ValueFunction object from a record which was saved into a file 01998 using the WriteFileRecord call. This is called by the base class 01999 loader routine ReadFileRecord, which finds an appropriate instance 02000 of a derived class to call to load the data in question. 02001 02002 This method creates a new instance of this particular ValueFunction class 02003 and then loads whatever information is necessary from the file to 02004 initialise itself properly. The record read-pointer is left pointing 02005 at the end of the ValueFunction-saved data so that the caller can continue 02006 reading their extra bytes of data after loading the ValueFunction. 02007 02008 SeeAlso: ValueFunctionRamp::WriteFileRecord 02009 02010 ******************************************************************************************/ 02011 02012 ValueFunction *ValueFunctionIntestine::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord) 02013 { 02014 ERROR3IF(pInputRecord == NULL, "Illegal NULL param"); 02015 02016 float Value1 = (float) 1.0; 02017 float Value2 = (float) 0.0; 02018 02019 pInputRecord->ReadFLOAT(&Value1); 02020 pInputRecord->ReadFLOAT(&Value2); 02021 02022 return(new ValueFunctionIntestine((double) Value1, (double) Value2)); 02023 } 02024 02025 /****************************************************************************************** 02026 02027 > virtual double ValueFunctionDecay::GetValue(double Position) 02028 02029 Author: Priestley (Xara Group Ltd) <camelotdev@xara.com> from Jason 02030 Created: 9/10/2000 02031 02032 Inputs: Position - A value between 0.0 and 1.0 02033 Returns: A value (between Value1 and Value2 given in the constructor) representing 02034 the value of the function at the given Position. 02035 02036 Purpose: To read the value of this function at a given position 02037 02038 ******************************************************************************************/ 02039 02040 double ValueFunctionDecay::GetValue(double Position) 02041 { 02042 const double MixValue = (1.0 - Position) * ((cos(Position * 20.0 * Pi) + 3.0) / 4.0); 02043 return MixValue; 02044 } 02045 02046 02047 02048 /****************************************************************************************** 02049 02050 > virtual ValueFunction *ValueFunctionDecay::Clone(void) 02051 02052 Author: Priestley (Xara Group Ltd) <camelotdev@xara.com> from Jason 02053 Created: 9/10/2000 02054 02055 Returns: NULL if it failed, else an exact copy of this object 02056 02057 Purpose: Clone operator. Creates an exact copy of this object 02058 02059 ******************************************************************************************/ 02060 02061 ValueFunction *ValueFunctionDecay::Clone(void) 02062 { 02063 ValueFunction *pClone = new ValueFunctionDecay(Value1, Value2); 02064 return(pClone); 02065 } 02066 02067 /****************************************************************************************** 02068 02069 > virtual INT32 ValueFunctionDecay::GetMinimumRecursionDepth(void) 02070 02071 Author: Priestley (Xara Group Ltd) <camelotdev@xara.com> 02072 Created: 9/10/2000 02073 02074 Purpose: Overriden function to indicate to the path stroker how many recursions to 02075 perform at minimum before declaring a line segment 'flat' enough 02076 02077 ******************************************************************************************/ 02078 02079 02080 INT32 ValueFunctionDecay::GetMinimumRecursionDepth() 02081 { 02082 return 4; 02083 } 02084 02085 02086 /****************************************************************************************** 02087 02088 > virtual ValueFunction *ValueFunctionDecay::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord) 02089 02090 Author: Priestley (Xara Group Ltd) <camelotdev@xara.com> from Jason 02091 Created: 9/10/2000 02092 02093 Inputs: pInputRecord - The file record to read 02094 02095 Returns: NULL if it failed, else a pointer to new ValueFunction object representing 02096 whatever was saved in that record. 02097 02098 Purpose: Loads a ValueFunction object from a record which was saved into a file 02099 using the WriteFileRecord call. This is called by the base class 02100 loader routine ReadFileRecord, which finds an appropriate instance 02101 of a derived class to call to load the data in question. 02102 02103 This method creates a new instance of this particular ValueFunction class 02104 and then loads whatever information is necessary from the file to 02105 initialise itself properly. The record read-pointer is left pointing 02106 at the end of the ValueFunction-saved data so that the caller can continue 02107 reading their extra bytes of data after loading the ValueFunction. 02108 02109 SeeAlso: ValueFunctionRamp::WriteFileRecord 02110 02111 ******************************************************************************************/ 02112 02113 ValueFunction *ValueFunctionDecay::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord) 02114 { 02115 ERROR3IF(pInputRecord == NULL, "Illegal NULL param"); 02116 02117 float Value1 = (float) 1.0; 02118 float Value2 = (float) 0.0; 02119 02120 pInputRecord->ReadFLOAT(&Value1); 02121 pInputRecord->ReadFLOAT(&Value2); 02122 02123 return(new ValueFunctionDecay((double) Value1, (double) Value2)); 02124 } 02125 02126 02127 02128 /****************************************************************************************** 02129 02130 > virtual double ValueFunctionBevelEnds::GetValue(double Position) 02131 02132 Author: Priestley (Xara Group Ltd) <camelotdev@xara.com> from Jason 02133 Created: 9/10/2000 02134 02135 Inputs: Position - A value between 0.0 and 1.0 02136 Returns: A value (between Value1 and Value2 given in the constructor) representing 02137 the value of the function at the given Position. 02138 02139 Purpose: To read the value of this function at a given position 02140 02141 Notes: Blobby is a half sine-wave "S" shaped function 02142 02143 ******************************************************************************************/ 02144 02145 double ValueFunctionBevelEnds::GetValue(double Position) 02146 { 02147 double Value; 02148 02149 if (Position == 1.0) 02150 { 02151 Value = 0.0; 02152 } 02153 else 02154 { 02155 if (Position < 0.15) 02156 { 02157 Position = Position / 0.15; 02158 Value = Position; 02159 } 02160 else 02161 { 02162 if (Position > 0.85) 02163 { 02164 Position = (Position - 0.85) / 0.15; 02165 Value = 1.0 - Position; 02166 } 02167 else 02168 { 02169 Value = 1.0; 02170 } 02171 } 02172 } 02173 02174 return Value; 02175 } 02176 02177 02178 02179 /****************************************************************************************** 02180 02181 > virtual ValueFunction *ValueFunctionBevelEnds::Clone(void) 02182 02183 Author: Priestley (Xara Group Ltd) <camelotdev@xara.com> from Jason 02184 Created: 9/10/2000 02185 02186 Returns: NULL if it failed, else an exact copy of this object 02187 02188 Purpose: Clone operator. Creates an exact copy of this object 02189 02190 ******************************************************************************************/ 02191 02192 ValueFunction *ValueFunctionBevelEnds::Clone(void) 02193 { 02194 ValueFunction *pClone = new ValueFunctionBevelEnds(Value1, Value2); 02195 return(pClone); 02196 } 02197 02198 02199 /****************************************************************************************** 02200 02201 > virtual INT32 ValueFunctionBevelEnds::GetMinimumRecursionDepth(void) 02202 02203 Author: Priestley (Xara Group Ltd) <camelotdev@xara.com> 02204 Created: 9/10/2000 02205 02206 Purpose: Overriden function to indicate to the path stroker how many recursions to 02207 perform at minimum before declaring a line segment 'flat' enough 02208 02209 ******************************************************************************************/ 02210 02211 INT32 ValueFunctionBevelEnds::GetMinimumRecursionDepth() 02212 { 02213 return 4; 02214 } 02215 02216 02217 /****************************************************************************************** 02218 02219 > virtual ValueFunction *ValueFunctionBevelEnds::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord) 02220 02221 Author: Priestley (Xara Group Ltd) <camelotdev@xara.com> from Jason 02222 Created: 9/10/2000 02223 02224 Inputs: pInputRecord - The file record to read 02225 02226 Returns: NULL if it failed, else a pointer to new ValueFunction object representing 02227 whatever was saved in that record. 02228 02229 Purpose: Loads a ValueFunction object from a record which was saved into a file 02230 using the WriteFileRecord call. This is called by the base class 02231 loader routine ReadFileRecord, which finds an appropriate instance 02232 of a derived class to call to load the data in question. 02233 02234 This method creates a new instance of this particular ValueFunction class 02235 and then loads whatever information is necessary from the file to 02236 initialise itself properly. The record read-pointer is left pointing 02237 at the end of the ValueFunction-saved data so that the caller can continue 02238 reading their extra bytes of data after loading the ValueFunction. 02239 02240 SeeAlso: ValueFunctionRamp::WriteFileRecord 02241 02242 ******************************************************************************************/ 02243 02244 ValueFunction *ValueFunctionBevelEnds::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord) 02245 { 02246 ERROR3IF(pInputRecord == NULL, "Illegal NULL param"); 02247 02248 float Value1 = (float) 1.0; 02249 float Value2 = (float) 0.0; 02250 02251 pInputRecord->ReadFLOAT(&Value1); 02252 pInputRecord->ReadFLOAT(&Value2); 02253 02254 return(new ValueFunctionBevelEnds((double) Value1, (double) Value2)); 02255 } 02256 02257 02258 02259 02260 02262 // ValueFunctionBlip and derived classes 02264 02265 /****************************************************************************************** 02266 02267 > ValueFunctionBlip::ValueFunctionBlip(double Value) 02268 02269 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02270 Created: 1/2/97 02271 02272 Inputs: MaxPosition - The position at which the function should reach 02273 its maximum value. Normally this is at 0.5, but 02274 for asymmetrical blips, values like 0.2 are better 02275 Purpose: Constructor 02276 02277 ******************************************************************************************/ 02278 02279 ValueFunctionBlip::ValueFunctionBlip(double MaxPosition) 02280 { 02281 ERROR3IF(MaxPosition <= 0.0 || MaxPosition >= 1.0, "Silly MaxPosition value"); 02282 MaxPos = MaxPosition; 02283 } 02284 02285 02286 02287 /****************************************************************************************** 02288 02289 > virtual double ValueFunctionBlip::GetValue(double Position) 02290 02291 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02292 Created: 1/2/97 02293 02294 Inputs: Position - A value between 0.0 and 1.0 02295 Returns: A value representing the value of the function at the given Position. 02296 02297 Purpose: To read the value of this function at a given position 02298 02299 Notes: This Blip is a 360 degree sine wave from 0.0 to 1.0 and back again. 02300 However, because the midpoint is adjustable, it is a piecewise function 02301 02302 ******************************************************************************************/ 02303 02304 double ValueFunctionBlip::GetValue(double Position) 02305 { 02306 double Value; 02307 if (Position < MaxPos) 02308 { 02309 Position /= MaxPos; 02310 Value = sin(Position * (Pi / 2.0)); 02311 } 02312 else 02313 { 02314 Position = (Position - MaxPos) / (1.0 - MaxPos); 02315 Value = cos(Position * (Pi / 2.0)); 02316 } 02317 02318 return(Value); 02319 } 02320 02321 02322 02323 /****************************************************************************************** 02324 02325 > virtual ValueFunction *ValueFunctionBlip::Clone(void) 02326 02327 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02328 Created: 1/2/97 02329 02330 Returns: NULL if it failed, else an exact copy of this object 02331 02332 Purpose: Clone operator. Creates an exact copy of this object 02333 02334 ******************************************************************************************/ 02335 02336 ValueFunction *ValueFunctionBlip::Clone(void) 02337 { 02338 ValueFunctionBlip *pClone = CreateInstance(); 02339 02340 if (pClone != NULL) 02341 pClone->MaxPos = MaxPos; 02342 02343 return(pClone); 02344 } 02345 02346 02347 02348 /****************************************************************************************** 02349 02350 > virtual BOOL ValueFunctionBlip::IsDifferent(ValueFunction *Other) 02351 02352 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02353 Created: 1/2/97 02354 02355 Inputs: pOther - Another ValueFunction object to compare this one to 02356 02357 Returns: TRUE if the objects are considered different, 02358 FALSE if they are considered identical 02359 02360 Purpose: Comparator. 02361 Determines if 2 different ValueFunction objects are considered 02362 different. 02363 02364 Notes: Calls the base class to see if they are different classes, 02365 and then compares identical classes by checking member vars 02366 02367 ******************************************************************************************/ 02368 02369 BOOL ValueFunctionBlip::IsDifferent(ValueFunction *pOther) 02370 { 02371 if (ValueFunction::IsDifferent(pOther)) 02372 return(TRUE); 02373 02374 // Both objects are instances of this class, so compare them more carefully 02375 return(MaxPos != ((ValueFunctionBlip *)pOther)->MaxPos); 02376 } 02377 02378 02379 02380 /****************************************************************************************** 02381 02382 > virtual CamelotFileRecord *ValueFunctionBlip::WriteFileRecord(INT32 RecordTag, 02383 INT32 ExtraBytes, BaseCamelotFilter *pFilter) 02384 02385 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02386 Created: 1/2/97 02387 02388 Inputs: RecordTag - the tag to write this record under 02389 ExtraBytes - The number of extra bytes of information the caller 02390 will write into the record after caling this function 02391 (Space for this many extra bytes will be reserved by 02392 this function when it creates the new file record) 02393 This may be 0 or more bytes. 02394 pFilter - The filter to write to 02395 02396 Returns: NULL if it failed, else a pointer to a record which saves the state 02397 of this valueFunction object. Once the caller has written the record, 02398 they MUST DELETE it. 02399 02400 Purpose: Saves a ValueFunction object to a Xara file. 02401 This function will create a new variable-sized record with the given 02402 record tag, and will write out whatever data is needed to save this 02403 ValueFunction's state to the file. 02404 02405 "ExtraBytes" bytes will be added to the record size to reserve space 02406 at the end of the record for the caller to add their own data. This 02407 is to allow ValueFunctions to be saved embedded in other object's 02408 record structures (e.g. inside different types of attributes). 02409 02410 All ValueFunction record data has 3 sections, whiich are recorded as follows: 02411 1. ValueFunction header, identifying which type of VF is being saved 02412 INT32 ValueFunctionUniqueID (4 bytes) 02413 2. Derived-class-data (0 or more bytes). This particular class adds: 02414 float MaxPosition (4 bytes) 02415 3. Caller data. This is written by the caller to the returned record 02416 object. This data must be ExtraBytes (0 or more) bytes in length. 02417 02418 SeeAlso: ValueFunctionBlip::CreateAndReadFileRecord 02419 02420 ******************************************************************************************/ 02421 02422 CamelotFileRecord *ValueFunctionBlip::WriteFileRecord(INT32 RecordTag, INT32 ExtraBytes, 02423 BaseCamelotFilter *pFilter) 02424 { 02425 ERROR3IF(pFilter == NULL, "Illegal NULL param"); 02426 ERROR3IF(ExtraBytes < 0, "Stupid ExtraBytes request in ValueFunction::WriteFileRecord"); 02427 02428 // Calculate how many bytes of information this VF will write. We do not include 02429 // the header info written by the base class or the ExtraInfo desired by the caller - 02430 // the base class adds all that in for us. 02431 const INT32 MyRecordSize = 4; 02432 02433 // Create an appropriate record, and write our data to it 02434 CamelotFileRecord *pRec = CreateAndWriteFileRecord(RecordTag, MyRecordSize, ExtraBytes, pFilter); 02435 02436 if (pRec != NULL) 02437 { 02438 // Write out our ValueFunction's specific data. If it fails, then we'll return NULL 02439 if (!pRec->WriteFLOAT((float)MaxPos)) 02440 { 02441 delete pRec; 02442 pRec = NULL; 02443 } 02444 } 02445 02446 return(pRec); 02447 } 02448 02449 02450 02451 /****************************************************************************************** 02452 02453 > virtual ValueFunction *ValueFunctionBlip::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord) 02454 02455 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02456 Created: 1/2/97 02457 02458 Inputs: pInputRecord - The file record to read 02459 02460 Returns: NULL if it failed, else a pointer to new ValueFunction object representing 02461 whatever was saved in that record. 02462 02463 Purpose: Loads a ValueFunction object from a record which was saved into a file 02464 using the WriteFileRecord call. This is called by the base class 02465 loader routine ReadFileRecord, which finds an appropriate instance 02466 of a derived class to call to load the data in question. 02467 02468 This method creates a new instance of this particular ValueFunction class 02469 and then loads whatever information is necessary from the file to 02470 initialise itself properly. The record read-pointer is left pointing 02471 at the end of the ValueFunction-saved data so that the caller can continue 02472 reading their extra bytes of data after loading the ValueFunction. 02473 02474 SeeAlso: ValueFunctionBlip::WriteFileRecord; 02475 ValueFunctionBlip::ReadFileRecord 02476 02477 ******************************************************************************************/ 02478 02479 ValueFunction *ValueFunctionBlip::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord) 02480 { 02481 ERROR3IF(pInputRecord == NULL, "Illegal NULL param"); 02482 02483 float MaxPosition = (float)0.5; 02484 pInputRecord->ReadFLOAT(&MaxPosition); 02485 02486 ValueFunctionBlip *pBlip = CreateInstance(); 02487 if (pBlip != NULL) 02488 pBlip->MaxPos = MaxPosition; 02489 02490 return(pBlip); 02491 } 02492 02493 02494 02495 /****************************************************************************************** 02496 02497 > virtual ValueFunctionBlip *ValueFunctionBlip::CreateInstance(void) 02498 02499 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02500 Created: 1/2/97 02501 02502 Returns: NULL if it failed, else a pointer to new ValueFunctionBlip object of 02503 the same type as "this" one. Used to allow derived Blip classes to 02504 use all the base class code, and merely override the GetValue method. 02505 02506 Purpose: Creates a new blank object of the same type as this one. Internal 02507 function used in ValueFunctionBlip & ValueFunctionBlipS. 02508 02509 Notes: Called by ValueFunctionBlip::Clone and CreateAndReadFileRecord, 02510 as this is the only action in those functions that depends on the type 02511 of the class that is being used 02512 02513 ******************************************************************************************/ 02514 02515 ValueFunctionBlip *ValueFunctionBlip::CreateInstance(void) 02516 { 02517 return(new ValueFunctionBlip); 02518 } 02519 02520 02521 02522 02523 02524 02525 02526 02527 /****************************************************************************************** 02528 02529 > virtual double ValueFunctionTeardrop::GetValue(double Position) 02530 02531 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02532 Created: 1/2/97 02533 02534 Inputs: Position - A value between 0.0 and 1.0 02535 Returns: A value representing the value of the function at the given Position. 02536 02537 Purpose: To read the value of this function at a given position 02538 02539 ******************************************************************************************/ 02540 02541 double ValueFunctionTeardrop::GetValue(double Position) 02542 { 02543 double Value; 02544 if (Position < MaxPos) 02545 { 02546 Position = 1.0 - Position/MaxPos; 02547 if ( Position>1.0 ) 02548 Position = 1.0; 02549 Value = sqrt(1-Position*Position); 02550 } 02551 else 02552 { 02553 Position = (Position - MaxPos) / (1.0 - MaxPos); 02554 Value = (cos( Position * Pi) + 1.0) / 2.0; 02555 } 02556 02557 return Value; 02558 } 02559 02560 02561 02562 /****************************************************************************************** 02563 02564 > virtual ValueFunctionBlip *ValueFunctionTeardrop::CreateInstance(void) 02565 02566 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02567 Created: 1/2/97 02568 02569 Returns: NULL if it failed, else a pointer to new ValueFunctionTeardrop object of 02570 the same type as "this" one. Used to allow derived Teardrop classes to 02571 use all the base class code, and merely override the GetValue method. 02572 02573 Purpose: Creates a new blank object of the same type as this one. Internal 02574 function used in ValueFunctionTeardrop & ValueFunctionTeardropS. 02575 02576 Notes: Called by ValueFunctionBlip::Clone and CreateAndReadFileRecord, 02577 as this is the only action in those functions that depends on the type 02578 of the class that is being used 02579 02580 ******************************************************************************************/ 02581 02582 ValueFunctionBlip *ValueFunctionTeardrop::CreateInstance(void) 02583 { 02584 return(new ValueFunctionTeardrop); 02585 } 02586 02587 02588 /****************************************************************************************** 02589 02590 > virtual double ValueFunctionTeardropCurvedEnd::GetValue(double Position) 02591 02592 Author: Priestley (Xara Group Ltd) <camelotdev@xara.com> from Jason 02593 Created: 9/10/2000 02594 02595 Inputs: Position - A value between 0.0 and 1.0 02596 Returns: A value representing the value of the function at the given Position. 02597 02598 Purpose: To read the value of this function at a given position 02599 02600 ******************************************************************************************/ 02601 02602 double ValueFunctionTeardropCurvedEnd::GetValue(double Position) 02603 { 02604 double Value; 02605 if (Position < 0.2) 02606 { 02607 Position = 1.0 - Position/0.2; 02608 if ( Position>1.0 ) 02609 Position = 1.0; 02610 Value = sqrt(1-Position*Position); 02611 } 02612 else 02613 { 02614 Position = (Position - 0.2) / 0.8; 02615 Value = sqrt(1.0 - Position); 02616 } 02617 02618 /* if (Position > 0.9) 02619 { 02620 Position = (Position - 0.9) / 0.1; 02621 Value = 0.4 * (cos(asin(Position))); 02622 } 02623 else 02624 { 02625 Position = (Position - 0.2) / 0.7; 02626 Value = ((1.0 - (Position * Position)) * 0.6) + 0.4; 02627 } 02628 } 02629 */ 02630 return(Value); 02631 } 02632 02633 02634 /****************************************************************************************** 02635 02636 > virtual INT32 ValueFunctionTeardropCurvedEnd::GetMinimumRecursionDepth(void) 02637 02638 Author: Priestley (Xara Group Ltd) <camelotdev@xara.com> 02639 Created: 9/10/2000 02640 02641 Purpose: Overriden function to indicate to the path stroker how many recursions to 02642 perform at minimum before declaring a line segment 'flat' enough 02643 02644 ******************************************************************************************/ 02645 02646 INT32 ValueFunctionTeardropCurvedEnd::GetMinimumRecursionDepth() 02647 { 02648 return 2; 02649 } 02650 02651 02652 /****************************************************************************************** 02653 02654 > virtual ValueFunctionBlip *ValueFunctionTeardropCurvedEnd::CreateInstance(void) 02655 02656 Author: Priestley (Xara Group Ltd) <camelotdev@xara.com> from Jason 02657 Created: 9/10/2000 02658 02659 Returns: NULL if it failed, else a pointer to new ValueFunctionTeardrop object of 02660 the same type as "this" one. Used to allow derived Teardrop classes to 02661 use all the base class code, and merely override the GetValue method. 02662 02663 Purpose: Creates a new blank object of the same type as this one. Internal 02664 function used in ValueFunctionTeardrop & ValueFunctionTeardropS. 02665 02666 Notes: Called by ValueFunctionBlip::Clone and CreateAndReadFileRecord, 02667 as this is the only action in those functions that depends on the type 02668 of the class that is being used 02669 02670 ******************************************************************************************/ 02671 02672 ValueFunctionBlip *ValueFunctionTeardropCurvedEnd::CreateInstance(void) 02673 { 02674 return(new ValueFunctionTeardropCurvedEnd); 02675 } 02676 02677 02678 02679 02680 02681 02682 02683 02684 /****************************************************************************************** 02685 02686 > virtual double ValueFunctionEllipse::GetValue(double Position) 02687 02688 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02689 Created: 1/2/97 02690 02691 Inputs: Position - A value between 0.0 and 1.0 02692 Returns: A value representing the value of the function at the given Position. 02693 02694 Purpose: To read the value of this function at a given position 02695 02696 ******************************************************************************************/ 02697 02698 double ValueFunctionEllipse::GetValue(double Position) 02699 { 02700 if (Position < MaxPos) 02701 Position = 1.0 - Position/MaxPos; 02702 else 02703 Position = (Position - MaxPos) / (1.0 - MaxPos); 02704 if ( Position>1.0 ) 02705 Position = 1.0; 02706 return sqrt(1-Position*Position); 02707 } 02708 02709 02710 02711 /****************************************************************************************** 02712 02713 > virtual ValueFunctionBlip *ValueFunctionEllipse::CreateInstance(void) 02714 02715 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02716 Created: 1/2/97 02717 02718 Returns: NULL if it failed, else a pointer to new ValueFunctionEllipse object of 02719 the same type as "this" one. Used to allow derived Ellipse classes to 02720 use all the base class code, and merely override the GetValue method. 02721 02722 Purpose: Creates a new blank object of the same type as this one. Internal 02723 function used in ValueFunctionEllipse & ValueFunctionEllipseS. 02724 02725 Notes: Called by ValueFunctionBlip::Clone and CreateAndReadFileRecord, 02726 as this is the only action in those functions that depends on the type 02727 of the class that is being used 02728 02729 ******************************************************************************************/ 02730 02731 ValueFunctionBlip *ValueFunctionEllipse::CreateInstance(void) 02732 { 02733 return(new ValueFunctionEllipse); 02734 } 02735 02736 02737 02738 02739 02740 02741 02742 02743 02744 /****************************************************************************************** 02745 02746 > virtual double ValueFunctionThumbtack::GetValue(double Position) 02747 02748 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02749 Created: 26/2/97 02750 02751 Inputs: Position - A value between 0.0 and 1.0 02752 Returns: A value representing the value of the function at the given Position. 02753 02754 Purpose: To read the value of this function at a given position 02755 02756 ******************************************************************************************/ 02757 02758 double ValueFunctionThumbtack::GetValue(double Position) 02759 { 02760 if (Position < MaxPos) 02761 Position = Position / MaxPos; 02762 else 02763 Position = 1.0 - ((Position - MaxPos) / (1.0 - MaxPos)); 02764 02765 if ( Position>1.0 ) 02766 Position = 1.0; 02767 return 1.0 - sqrt(1-Position*Position); 02768 } 02769 02770 02771 02772 /****************************************************************************************** 02773 02774 > virtual ValueFunctionBlip *ValueFunctionThumbtack::CreateInstance(void) 02775 02776 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02777 Created: 26/2/97 02778 02779 Returns: NULL if it failed, else a pointer to new ValueFunctionThumbtack object of 02780 the same type as "this" one. Used to allow derived Thumbtack classes to 02781 use all the base class code, and merely override the GetValue method. 02782 02783 Purpose: Creates a new blank object of the same type as this one. Internal 02784 function used in ValueFunctionThumbtack & ValueFunctionThumbtackS. 02785 02786 Notes: Called by ValueFunctionBlip::Clone and CreateAndReadFileRecord, 02787 as this is the only action in those functions that depends on the type 02788 of the class that is being used 02789 02790 ******************************************************************************************/ 02791 02792 ValueFunctionBlip *ValueFunctionThumbtack::CreateInstance(void) 02793 { 02794 return(new ValueFunctionThumbtack); 02795 } 02796 02797 02798 02799 02800 02801 02803 // ValueFunctionPressure classes 02805 02806 02807 /****************************************************************************************** 02808 02809 > ValueFunctionPressure::ValueFunctionPressure() 02810 02811 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02812 Created: 20/1/97 02813 02814 Purpose: Constructor 02815 Pressure functions store a table of recorded pressure values and 02816 return curve-interpolated pressure values on demand. 02817 02818 ******************************************************************************************/ 02819 02820 ValueFunctionPressure::ValueFunctionPressure() 02821 { 02822 pArray = NULL; 02823 ArraySize = 0; 02824 NextFree = 0; 02825 } 02826 02827 02828 02829 /****************************************************************************************** 02830 02831 > ValueFunctionPressure::~ValueFunctionPressure() 02832 02833 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02834 Created: 20/1/97 02835 02836 Purpose: Destructor 02837 02838 ******************************************************************************************/ 02839 02840 ValueFunctionPressure::~ValueFunctionPressure() 02841 { 02842 if (pArray != NULL) 02843 CCFree(pArray); 02844 } 02845 02846 02847 02848 /****************************************************************************************** 02849 02850 > virtual double ValueFunctionPressure::GetValue(double Position) 02851 02852 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02853 Created: 20/1/97 02854 02855 Inputs: Position - A value between 0.0 and 1.0 02856 Returns: A value representing the recorded pressure at the given Position. 02857 02858 Purpose: To read the value of this function at a given position 02859 02860 Notes: This determines the 2 closest position values for which pressure 02861 information was recorded, and interpolates the values by "fitting a 02862 curve" through the points. 02863 02864 The "curve" may be improved in future, but is currently a simple 02865 linear interpolation. 02866 02867 ****!!!!TODO: This should cache the last array index it was asked for, 02868 and start the search from that index, as we usually ask for values for 02869 sequential, close, position values, and this will vastly reduce the 02870 searching overhead in most cases. Note that we may step through 02871 positions in both positive & negative directions, so it will have 02872 to handle this carefully. 02873 02874 ******************************************************************************************/ 02875 02876 double ValueFunctionPressure::GetValue(double Position) 02877 { 02878 // No entries have been recorded! 02879 if (NextFree < 1) 02880 return(0.0); 02881 02882 // If the position is outside the range in our table, return the closest entry 02883 if (Position <= pArray[0].Position) 02884 return(pArray[0].Pressure); 02885 02886 if (Position >= pArray[NextFree-1].Position) 02887 return(pArray[NextFree-1].Pressure); 02888 02889 // Search to find the closest 2 array entries to the position 02890 // We assume the array fills the 0.0 to 1.0 range, so we search from the closest 02891 // "end" of the array to halve the average search time. 02892 INT32 i; 02893 if (Position >= 0.5) 02894 { 02895 i = NextFree; 02896 while (i > 1 && Position < pArray[i-1].Position) 02897 i--; 02898 } 02899 else 02900 { 02901 i = 1; 02902 while (i < NextFree && Position > pArray[i].Position) 02903 i++; 02904 } 02905 02906 ERROR3IF(i < 1 || i >= NextFree, "I've screwed up the scanning loop code"); 02907 02908 // Otherwise, the position lies between array elements [i-1] and [i], so we 02909 // interpolate between these positions 02910 ERROR3IF((pArray[i].Position - pArray[i-1].Position) <= 0.0, "Pressure array is non-ascending!"); 02911 const double MixValue = (Position - pArray[i-1].Position) / 02912 (pArray[i].Position - pArray[i-1].Position); 02913 02914 return((MixValue * pArray[i].Pressure) + ((1.0 - MixValue) * pArray[i-1].Pressure)); 02915 } 02916 02917 02918 02919 /****************************************************************************************** 02920 02921 > virtual ValueFunction *ValueFunctionPressure::Clone(void) 02922 02923 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02924 Created: 20/1/97 02925 02926 Returns: NULL if it failed, else an exact copy of this object 02927 02928 Purpose: Clone operator. Creates an exact copy of this object 02929 02930 ******************************************************************************************/ 02931 02932 ValueFunction *ValueFunctionPressure::Clone(void) 02933 { 02934 // Create another object of this type 02935 ValueFunctionPressure *pClone = CreateInstance(); 02936 02937 if (pClone != NULL) 02938 { 02939 // If that worked, make it allocate an array large enough to hold a copy of 02940 // our data, and memcpy the array across. 02941 if (pClone->ExpandArray(NextFree)) 02942 { 02943 // We only copy the used array entries so the clone will have no wasted space in it 02944 memcpy(pClone->pArray, pArray, NextFree * sizeof(VFPressureRecord)); 02945 pClone->NextFree = NextFree; 02946 pClone->ArraySize = NextFree; 02947 } 02948 } 02949 02950 return(pClone); 02951 } 02952 02953 02954 02955 /****************************************************************************************** 02956 02957 > virtual BOOL ValueFunctionPressure::IsDifferent(ValueFunction *Other) 02958 02959 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02960 Created: 20/1/97 02961 02962 Inputs: pOther - Another ValueFunction object to compare this one to 02963 02964 Returns: TRUE if the objects are considered different, 02965 FALSE if they are considered identical 02966 02967 Purpose: Comparator. 02968 Determines if 2 different ValueFunction objects are considered 02969 different. 02970 02971 Notes: Calls the base class to see if they are different classes, 02972 and then compares identical classes by checking member vars 02973 02974 ******************************************************************************************/ 02975 02976 BOOL ValueFunctionPressure::IsDifferent(ValueFunction *pOther) 02977 { 02978 if (ValueFunction::IsDifferent(pOther)) 02979 return(TRUE); 02980 02981 // Both objects are instances of this class, so compare them more carefully 02982 ValueFunctionPressure *pPressure = (ValueFunctionPressure *)pOther; 02983 if (NextFree != pPressure->NextFree) 02984 return(TRUE); // Don't have same number of entries 02985 02986 // Now compare the entire array 02987 for (INT32 i = 0; i < NextFree; i++) 02988 { 02989 if (pArray[i].Position != pPressure->pArray[i].Position || 02990 pArray[i].Pressure != pPressure->pArray[i].Pressure) 02991 { 02992 return(TRUE); 02993 } 02994 } 02995 02996 // Cor. They must be the same! 02997 return(FALSE); 02998 } 02999 03000 03001 03002 /****************************************************************************************** 03003 03004 > BOOL ValueFunctionPressure::AddPressure(float Position, BYTE PressureValue) 03005 03006 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 03007 Created: 20/1/97 03008 03009 Inputs: Position - A number representing distance along the path of this point 03010 (Normally this would be between 0.0 and 1.0, but you can temporarily 03011 use positions between 0.0 and any positive value and then call 03012 NormalisePositions if this is more convenient while building the table) 03013 03014 NOTE: Each added pressure value must be a positive number, and must 03015 be greater than the last in order to be recorded. Illegal values 03016 will be discarded. 03017 03018 PressureValue - The pressure value to record for this position 03019 03020 Returns: FALSE if memory was unavailable 03021 TRUE if it was happy (even if it discarded the value) 03022 03023 Purpose: Adds a pressure record to the ValueFunction table. 03024 03025 ******************************************************************************************/ 03026 03027 BOOL ValueFunctionPressure::AddPressure(float Position, float PressureValue) 03028 { 03029 ERROR3IF(PressureValue < 0.0 || PressureValue > 1.0, "Illegal pressure value"); 03030 ERROR3IF(Position < 0.0, "Illegal (negative) position value"); 03031 03032 // Make sure there's plenty of room for new entries 03033 if (NextFree >= ArraySize && !ExpandArray(ArraySize + 32)) 03034 return(FALSE); 03035 03036 // Only record the value if the position has advanced. Error if the position has 03037 // gone retrograde, but quietly dismiss equal positions. 03038 ERROR3IF(NextFree > 0 && Position < pArray[NextFree-1].Position, 03039 "AddPressure - pressure values must be ascending"); 03040 if (NextFree > 0 && Position <= pArray[NextFree-1].Position) 03041 return(TRUE); 03042 03043 // And write this entry 03044 pArray[NextFree].Position = Position; 03045 pArray[NextFree].Pressure = PressureValue; 03046 NextFree++; 03047 03048 return(TRUE); 03049 } 03050 03051 03052 03053 /****************************************************************************************** 03054 03055 > void ValueFunctionPressure::NormalisePositions(void) 03056 03057 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 03058 Created: 20/1/97 03059 03060 Purpose: Normalises all positions in the table to lie within a 0.0 to 1.0 range, 03061 by dividing them by the last element position value. (i.e. it assumes that 03062 the last element in the array will have the largest Position value) 03063 03064 ******************************************************************************************/ 03065 03066 void ValueFunctionPressure::NormalisePositions(void) 03067 { 03068 // If fewer than 1 entries, or no array, then there's nothing to do 03069 if (pArray == NULL || NextFree < 1) 03070 return; 03071 03072 // Find the maximum value, and baulk if it would cause a divide by zero. 03073 if (pArray[NextFree-1].Position <= 0.0) 03074 { 03075 ERROR3("Max position in table is zero or negative - normalisation failed"); 03076 return; 03077 } 03078 03079 float RMaxPosition = 1.0/pArray[NextFree-1].Position; 03080 for (INT32 i = 0; i < NextFree; i++) 03081 pArray[i].Position *= RMaxPosition; 03082 } 03083 03084 03085 03086 /****************************************************************************************** 03087 03088 > BOOL ValueFunctionPressure::ExpandArray(INT32 NewSize) 03089 03090 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 03091 Created: 20/1/97 03092 03093 Inputs: NewSize - The number of array entries desired. 03094 03095 Returns: FALSE if memory was unavailable 03096 03097 Purpose: Ensures that the pressure storage array has no fewer than NewSize entries. 03098 03099 Notes: For efficiency, unused array entries are always left uninitialised 03100 03101 ******************************************************************************************/ 03102 03103 BOOL ValueFunctionPressure::ExpandArray(INT32 NewSize) 03104 { 03105 if (NewSize <= ArraySize) 03106 return(TRUE); // That was easy! 03107 03108 VFPressureRecord *pNewArray = NULL; 03109 03110 if (pArray == NULL) 03111 pNewArray = (VFPressureRecord *) CCMalloc(NewSize * sizeof(VFPressureRecord)); 03112 else 03113 pNewArray = (VFPressureRecord *) CCRealloc(pArray, NewSize * sizeof(VFPressureRecord)); 03114 03115 if (pNewArray == NULL) 03116 return(FALSE); 03117 03118 // We succeeded, so remember the new address & size 03119 pArray = pNewArray; 03120 ArraySize = NewSize; 03121 03122 return(TRUE); 03123 } 03124 03125 03126 03127 /****************************************************************************************** 03128 03129 > virtual CamelotFileRecord *ValueFunctionPressure::WriteFileRecord(INT32 RecordTag, 03130 INT32 ExtraBytes, BaseCamelotFilter *pFilter) 03131 03132 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 03133 Created: 27/1/97 03134 03135 Inputs: RecordTag - the tag to write this record under 03136 ExtraBytes - The number of extra bytes of information the caller 03137 will write into the record after caling this function 03138 (Space for this many extra bytes will be reserved by 03139 this function when it creates the new file record) 03140 This may be 0 or more bytes. 03141 pFilter - The filter to write to 03142 03143 Returns: NULL if it failed, else a pointer to a record which saves the state 03144 of this valueFunction object. Once the caller has written the record, 03145 they MUST DELETE it. 03146 03147 Purpose: Saves a ValueFunction object to a Xara file. 03148 This function will create a new variable-sized record with the given 03149 record tag, and will write out whatever data is needed to save this 03150 ValueFunction's state to the file. 03151 03152 "ExtraBytes" bytes will be added to the record size to reserve space 03153 at the end of the record for the caller to add their own data. This 03154 is to allow ValueFunctions to be saved embedded in other object's 03155 record structures (e.g. inside different types of attributes). 03156 03157 All ValueFunction record data has 3 sections, whiich are recorded as follows: 03158 1. ValueFunction header, identifying which type of VF is being saved 03159 INT32 ValueFunctionUniqueID (4 bytes) 03160 2. Derived-class-data (0 or more bytes). This particular class adds: 03161 UINT32 NumTableEntries 03162 + n entries of the form: 03163 UNIT16 Position 03164 UINT16 Pressure (4 + (NumTableEntries*4) bytes) 03165 3. Caller data. This is written by the caller to the returned record 03166 object. This data must be ExtraBytes (0 or more) bytes in length. 03167 03168 The Position & Pressure values are 16-bit unsigned values between 03169 0 & 65535. These represent floating point values between 0.0 & 1.0, 03170 i.e. are simply a (UINT16) (Value * 65535.0). I don't bother avoiding 03171 rounding errors, as 1/128000th is an insignificant error. 03172 03173 SeeAlso: ValueFunctionPressure::CreateAndReadFileRecord; 03174 ValueFunction::CreateAndWriteFileRecord 03175 03176 ******************************************************************************************/ 03177 03178 CamelotFileRecord *ValueFunctionPressure::WriteFileRecord(INT32 RecordTag, INT32 ExtraBytes, 03179 BaseCamelotFilter *pFilter) 03180 { 03181 ERROR3IF(pFilter == NULL, "Illegal NULL param"); 03182 ERROR3IF(ExtraBytes < 0, "Stupid ExtraBytes request in ValueFunction::WriteFileRecord"); 03183 03184 // Calculate how many bytes of information this VF will write. We do not include 03185 // the header info written by the base class or the ExtraInfo desired by the caller - 03186 // the base class adds all that in for us. 03187 const INT32 MyRecordSize = 4 + (4 * NextFree); 03188 03189 // Create an appropriate record, and write our data to it 03190 CamelotFileRecord *pRec = CreateAndWriteFileRecord(RecordTag, MyRecordSize, ExtraBytes, pFilter); 03191 03192 if (pRec != NULL) 03193 { 03194 BOOL ok = TRUE; 03195 if (ok) ok = pRec->WriteUINT32((UINT32) NextFree); 03196 03197 for (INT32 i = 0; (i < NextFree) && ok; i++) 03198 { 03199 if (ok) ok = pRec->WriteUINT16((UINT16) (pArray[i].Position * 65535.0)); 03200 if (ok) ok = pRec->WriteUINT16((UINT16) (pArray[i].Pressure * 65535.0)); 03201 } 03202 03203 if (!ok) // If we failed, clean up & return NULL 03204 { 03205 delete pRec; 03206 pRec = NULL; 03207 } 03208 } 03209 03210 return(pRec); 03211 } 03212 03213 03214 03215 /****************************************************************************************** 03216 03217 > virtual ValueFunction *ValueFunctionPressure::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord) 03218 03219 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 03220 Created: 27/1/97 03221 03222 Inputs: pInputRecord - The file record to read 03223 03224 Returns: NULL if it failed, else a pointer to new ValueFunction object representing 03225 whatever was saved in that record. 03226 03227 Purpose: Loads a ValueFunction object from a record which was saved into a file 03228 using the WriteFileRecord call. This is called by the base class 03229 loader routine ReadFileRecord, which finds an appropriate instance 03230 of a derived class to call to load the data in question. 03231 03232 This method creates a new instance of this particular ValueFunction class 03233 and then loads whatever information is necessary from the file to 03234 initialise itself properly. The record read-pointer is left pointing 03235 at the end of the ValueFunction-saved data so that the caller can continue 03236 reading their extra bytes of data after loading the ValueFunction. 03237 03238 SeeAlso: ValueFunctionPressure::WriteFileRecord 03239 03240 ******************************************************************************************/ 03241 03242 ValueFunction *ValueFunctionPressure::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord) 03243 { 03244 ERROR3IF(pInputRecord == NULL, "Illegal NULL param"); 03245 03246 UINT32 NumEntries = 0; 03247 pInputRecord->ReadUINT32(&NumEntries); 03248 03249 ValueFunctionPressure *pValFunc = CreateInstance(); 03250 03251 if (pValFunc != NULL && NumEntries > 0) 03252 { 03253 // Make the array big enough to hold all the entries, to save reallocing it as we go, 03254 // and also to save us having to check for failure on each pressure item we add. 03255 if (!pValFunc->ExpandArray(NumEntries)) 03256 { 03257 delete pValFunc; 03258 return(NULL); 03259 } 03260 03261 UINT16 Position; 03262 UINT16 Pressure; 03263 03264 for (UINT32 i = 0; i < NumEntries; i++) 03265 { 03266 pInputRecord->ReadUINT16(&Position); 03267 pInputRecord->ReadUINT16(&Pressure); 03268 pValFunc->AddPressure( ((float)Position) / (float) 65535.0, 03269 ((float)Pressure) / (float) 65535.0); 03270 } 03271 } 03272 03273 return(pValFunc); 03274 } 03275 03276 03277 03278 /****************************************************************************************** 03279 03280 > virtual ValueFunctionPressure *ValueFunctionPressure::CreateInstance(void) 03281 03282 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 03283 Created: 27/1/97 03284 03285 Returns: NULL if it failed, else a pointer to new ValueFunctionPressure object of 03286 the same type as "this" one. Used to allow derived Pressure classes to 03287 use all the base class code, and merely override the GetValue method. 03288 03289 Purpose: Creates a new blank object of the same type as this one. Internal 03290 function used in ValueFunctionPressure & ValueFunctionPressureS. 03291 03292 Notes: Called by ValueFunctionPressure::Clone and CreateAndReadFileRecord, 03293 as this is the only action in those functions that depends on the type 03294 of the class that is being used 03295 03296 ******************************************************************************************/ 03297 03298 ValueFunctionPressure *ValueFunctionPressure::CreateInstance(void) 03299 { 03300 return(new ValueFunctionPressure); 03301 } 03302 03303 03304 03305 03306 03307 03308 03309 03310 /****************************************************************************************** 03311 03312 > virtual double ValueFunctionPressureS::GetValue(double Position) 03313 03314 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 03315 Created: 31/1/97 03316 03317 Inputs: Position - A value between 0.0 and 1.0 03318 Returns: A value representing the recorded pressure at the given Position. 03319 03320 Purpose: To read the value of this function at a given position 03321 03322 Notes: This determines the 2 closest position values for which pressure 03323 information was recorded, and interpolates the values by "fitting a 03324 curve" through the points. 03325 03326 The "curve" may be improved in future, but is currently a simple 03327 linear interpolation. 03328 03329 ****!!!!TODO: This could cache the last array index it was asked for, 03330 and start the search from that index, as we usually ask for values for 03331 sequential, close, position values, and this will reduce the 03332 searching overhead in most cases. Note that we may step through 03333 positions in both positive & negative directions, so it will have 03334 to handle this carefully. Note that PressureS functions seldom have 03335 very many samples recorded in their tables, due to my wonderfully 03336 rampant smoothing, so this may not turn out to be very beneficial. 03337 03338 ******************************************************************************************/ 03339 03340 double ValueFunctionPressureS::GetValue(double Position) 03341 { 03342 // No entries have been recorded! 03343 if (NextFree < 1) 03344 return(0.0); 03345 03346 // If the position is outside the range in our table, return the closest entry 03347 if (Position <= pArray[0].Position) 03348 return(pArray[0].Pressure); 03349 03350 if (Position >= pArray[NextFree-1].Position) 03351 return(pArray[NextFree-1].Pressure); 03352 03353 // Search to find the closest 2 array entries to the position 03354 // We assume the array fills the 0.0 to 1.0 range, so we search from the closest 03355 // "end" of the array to halve the average search time. 03356 INT32 i; 03357 if (Position >= 0.5) 03358 { 03359 i = NextFree; 03360 while (i > 1 && Position < pArray[i-1].Position) 03361 i--; 03362 } 03363 else 03364 { 03365 i = 1; 03366 while (i < NextFree && Position > pArray[i].Position) 03367 i++; 03368 } 03369 03370 ERROR3IF(i < 1 || i >= NextFree, "I've screwed up the scanning loop code (1)"); 03371 ERROR3IF(Position < pArray[i-1].Position || Position > pArray[i].Position, 03372 "I've screwed up the scanning loop code (2)"); 03373 03374 // Otherwise, the position lies between array elements [i-1] and [i], so we 03375 // interpolate between these positions 03376 ERROR3IF((pArray[i].Position - pArray[i-1].Position) <= 0.0, "Pressure array is non-ascending!"); 03377 double MixValue = (Position - pArray[i-1].Position) / 03378 (pArray[i].Position - pArray[i-1].Position); 03379 03380 // And convert the linear mix value into a nice S-curve (180 degrees of sine wave) 03381 // We use a different function on the first and last segments so that you get nicer 03382 // ends to your strokes. (90 degrees of sine wave) 03383 if (i < 2 || i >= NextFree - 1) 03384 MixValue = cos(-MixValue * (Pi / 2.0)); 03385 else 03386 MixValue = (cos(MixValue * Pi) + 1.0) / 2.0; 03387 03388 return((MixValue * pArray[i-1].Pressure) + ((1.0 - MixValue) * pArray[i].Pressure)); 03389 } 03390 03391 03392 03393 /****************************************************************************************** 03394 03395 > virtual ValueFunctionPressure *ValueFunctionPressureS::CreateInstance(void) 03396 03397 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 03398 Created: 31/1/97 03399 03400 Returns: NULL if it failed, else a pointer to new ValueFunctionPressure object of 03401 the same type as "this" one. Used to allow derived Pressure classes to 03402 use all the base class code, and merely override the GetValue method. 03403 03404 Purpose: Creates a new blank object of the same type as this one. Internal 03405 function used in ValueFunctionPressure & ValueFunctionPressureS. 03406 03407 ******************************************************************************************/ 03408 03409 ValueFunctionPressure *ValueFunctionPressureS::CreateInstance(void) 03410 { 03411 return(new ValueFunctionPressureS); 03412 } 03413 03414 03415 03416 03417 03419 // ValueFunctionSmoothStroke classes 03421 03422 03423 /****************************************************************************************** 03424 03425 > ValueFunctionSmoothStroke::ValueFunctionSmoothStroke() 03426 03427 Author: Priestley (Xara Group Ltd) <camelotdev@xara.com> 03428 Created: 10/10/2000 03429 03430 Purpose: Constructor 03431 03432 ******************************************************************************************/ 03433 03434 ValueFunctionSmoothStroke::ValueFunctionSmoothStroke(double newValue1y, double newValue2x, double newValue2y, double newValue3x, double newValue3y, double newValue4y) 03435 { 03436 Value1y = newValue1y; 03437 Value2x = newValue2x; 03438 Value2y = newValue2y; 03439 Value3x = newValue3x; 03440 Value3y = newValue3y; 03441 Value4y = newValue4y; 03442 } 03443 03444 ValueFunctionSmoothStroke::~ValueFunctionSmoothStroke() 03445 { 03446 } 03447 03448 /****************************************************************************************** 03449 03450 > virtual BOOL ValueFunctionSmoothStroke::IsDifferent(ValueFunction *Other) 03451 03452 Author: Priestley (Xara Group Ltd) <camelotdev@xara.com> 03453 Created: 10/10/2000 03454 03455 Inputs: pOther - Another ValueFunction object to compare this one to 03456 03457 Returns: TRUE if the objects are considered different, 03458 FALSE if they are considered identical 03459 03460 Purpose: Comparator. 03461 Determines if 2 different ValueFunction objects are considered 03462 different. 03463 03464 Notes: Calls the base class to see if they are different classes, 03465 and then compares identical classes by checking member vars 03466 03467 ******************************************************************************************/ 03468 03469 BOOL ValueFunctionSmoothStroke::IsDifferent(ValueFunction *pOther) 03470 { 03471 if (ValueFunction::IsDifferent(pOther)) 03472 { 03473 return(true); 03474 } 03475 // Both objects are instances of this class, so compare them more carefully 03476 return( (Value1y != ((ValueFunctionSmoothStroke *)pOther)->Value1y) || 03477 (Value2x != ((ValueFunctionSmoothStroke *)pOther)->Value2x) || 03478 (Value2y != ((ValueFunctionSmoothStroke *)pOther)->Value2y) || 03479 (Value3x != ((ValueFunctionSmoothStroke *)pOther)->Value3x) || 03480 (Value3y != ((ValueFunctionSmoothStroke *)pOther)->Value3y) || 03481 (Value4y != ((ValueFunctionSmoothStroke *)pOther)->Value4y) ) ; 03482 } 03483 03484 03485 /****************************************************************************************** 03486 03487 > virtual CamelotFileRecord *ValueFunctionSmoothStroke::WriteFileRecord(INT32 RecordTag, 03488 INT32 ExtraBytes, BaseCamelotFilter *pFilter) 03489 03490 Author: Priestley (Xara Group Ltd) <camelotdev@xara.com> 03491 Created: 10/10/2000 03492 03493 Inputs: RecordTag - the tag to write this record under 03494 ExtraBytes - The number of extra bytes of information the caller 03495 will write into the record after caling this function 03496 (Space for this many extra bytes will be reserved by 03497 this function when it creates the new file record) 03498 This may be 0 or more bytes. 03499 pFilter - The filter to write to 03500 03501 Returns: NULL if it failed, else a pointer to a record which saves the state 03502 of this valueFunction object. Once the caller has written the record, 03503 they MUST DELETE it. 03504 03505 Purpose: Saves a ValueFunction object to a Xara file. 03506 This function will create a new variable-sized record with the given 03507 record tag, and will write out whatever data is needed to save this 03508 ValueFunction's state to the file. 03509 03510 ******************************************************************************************/ 03511 03512 CamelotFileRecord *ValueFunctionSmoothStroke::WriteFileRecord(INT32 RecordTag, INT32 ExtraBytes, 03513 BaseCamelotFilter *pFilter) 03514 { 03515 ERROR3IF(pFilter == NULL, "Illegal NULL param"); 03516 ERROR3IF(ExtraBytes < 0, "Stupid ExtraBytes request in ValueFunction::WriteFileRecord"); 03517 03518 const INT32 MyRecordSize = 24; 03519 03520 // Create an appropriate record, and write our data to it 03521 CamelotFileRecord *pRec = CreateAndWriteFileRecord(RecordTag, MyRecordSize, ExtraBytes, pFilter); 03522 03523 if (pRec != NULL) 03524 { 03525 BOOL ok = TRUE; 03526 if (ok) ok = pRec->WriteFLOAT((FLOAT) Value1y); 03527 if (ok) ok = pRec->WriteFLOAT((FLOAT) Value2x); 03528 if (ok) ok = pRec->WriteFLOAT((FLOAT) Value2y); 03529 if (ok) ok = pRec->WriteFLOAT((FLOAT) Value3x); 03530 if (ok) ok = pRec->WriteFLOAT((FLOAT) Value3y); 03531 if (ok) ok = pRec->WriteFLOAT((FLOAT) Value4y); 03532 03533 if (!ok) // If we failed, clean up & return NULL 03534 { 03535 delete pRec; 03536 pRec = NULL; 03537 } 03538 } 03539 03540 return(pRec); 03541 } 03542 03543 03544 /****************************************************************************************** 03545 03546 > virtual ValueFunction *ValueFunctionSmoothStroke::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord) 03547 03548 Author: Priestley (Xara Group Ltd) <camelotdev@xara.com> 03549 Created: 10/10/2000 03550 03551 Inputs: pInputRecord - The file record to read 03552 03553 Returns: NULL if it failed, else a pointer to new ValueFunction object representing 03554 whatever was saved in that record. 03555 03556 Purpose: Loads a ValueFunction object from a record which was saved into a file 03557 using the WriteFileRecord call. This is called by the base class 03558 loader routine ReadFileRecord, which finds an appropriate instance 03559 of a derived class to call to load the data in question. 03560 03561 ******************************************************************************************/ 03562 03563 ValueFunction *ValueFunctionSmoothStroke::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord) 03564 { 03565 ERROR3IF(pInputRecord == NULL, "Illegal NULL param"); 03566 03567 float newValue1y = 0.0; 03568 float newValue2x = 0.0; 03569 float newValue2y = 0.0; 03570 float newValue3x = 0.0; 03571 float newValue3y = 0.0; 03572 float newValue4y = 0.0; 03573 03574 pInputRecord->ReadFLOAT(&newValue1y); 03575 pInputRecord->ReadFLOAT(&newValue2x); 03576 pInputRecord->ReadFLOAT(&newValue2y); 03577 pInputRecord->ReadFLOAT(&newValue3x); 03578 pInputRecord->ReadFLOAT(&newValue3y); 03579 pInputRecord->ReadFLOAT(&newValue4y); 03580 03581 03582 ValueFunctionSmoothStroke *pSStroke = CreateInstance(); 03583 if (pSStroke != NULL) 03584 { 03585 pSStroke->Value1y = newValue1y; 03586 pSStroke->Value2x = newValue2x; 03587 pSStroke->Value2y = newValue2y; 03588 pSStroke->Value3x = newValue3x; 03589 pSStroke->Value3y = newValue3y; 03590 pSStroke->Value4y = newValue4y; 03591 } 03592 03593 return(pSStroke); 03594 } 03595 03596 03597 /****************************************************************************************** 03598 03599 > virtual ValueFunctionSmoothStroke *ValueFunctionSmoothStroke::CreateInstance(void) 03600 03601 Author: Priestley (Xara Group Ltd) <camelotdev@xara.com> 03602 Created: 10/10/2000 03603 03604 Returns: NULL if it failed, else a pointer to new ValueFunctionSmoothStroke object of 03605 the same type as "this" one. 03606 03607 ******************************************************************************************/ 03608 03609 ValueFunctionSmoothStroke *ValueFunctionSmoothStroke::CreateInstance(void) 03610 { 03611 //You shouldn't really be calling this base class CreateInstance() so Fail! 03612 return NULL; 03613 } 03614 03615 03616 /****************************************************************************************** 03617 03618 > virtual INT32 ValueFunctionSmoothStroke::GetMinimumRecursionDepth(void) 03619 03620 Author: Priestley (Xara Group Ltd) <camelotdev@xara.com> 03621 Created: 9/10/2000 03622 03623 Purpose: Overriden function to indicate to the path stroker how many recursions to 03624 perform at minimum before declaring a line segment 'flat' enough 03625 03626 ******************************************************************************************/ 03627 03628 INT32 ValueFunctionSmoothStroke::GetMinimumRecursionDepth() 03629 { 03630 return 2; 03631 } 03632 03633 03634 03635 /****************************************************************************************** 03636 03637 > virtual double ValueFunctionSmoothStroke::GetValue(double Position) 03638 03639 Author: Priestley (Xara Group Ltd) <camelotdev@xara.com> 03640 Created: 10/10/2000 03641 03642 Inputs: Position - A value between 0.0 and 1.0 03643 Returns: A value (between Value1 and Value2 given in the constructor) representing 03644 the value of the function at the given Position. 03645 03646 Purpose: To read the value of this function at a given position 03647 03648 ******************************************************************************************/ 03649 03650 double ValueFunctionSmoothStroke::GetValue(double Position) 03651 { 03652 //Which ValueFunction are we looking at? 03653 INT32 index = (INT32)GetUniqueID(); 03654 index -= (INT32)ValueFunctionID_BevelEnds + 1; 03655 03656 03657 INT32 counter; 03658 03659 //Find the first xvalue which is greater than or equal to our position 03660 for (counter = 0; counter < 256; counter++) 03661 { 03662 if (xvalue[index][counter] >= Position) 03663 { 03664 //Stop looking through the array when we have found it! 03665 break; 03666 } 03667 } 03668 03669 if (counter > 0) 03670 { 03671 counter -= 1; 03672 } 03673 03674 //Work out how far through between xvalue[counter] and xvalue[counter+1] we are, then multiply 03675 //this by the vertical difference of the two coordinates, then add on yvalue[counter] to get the 03676 //approximate value at this Position... 03677 double xdifference = xvalue[index][counter+1] - xvalue[index][counter]; 03678 double ydifference = yvalue[index][counter+1] - yvalue[index][counter]; 03679 03680 //Now just check to make sure that we aren't about to divide by zero! 03681 if (xdifference == 0.0) 03682 { 03683 //Set to a very small number... 03684 xdifference = 0.0000000000000001; 03685 } 03686 03687 double value = yvalue[index][counter] + (((Position - xvalue[index][counter]) / xdifference) * ydifference); 03688 03689 return value; 03690 } 03691 03692 03693 03694 03695 void ValueFunctionSmoothStroke::MakeTable() 03696 { 03697 //Which ValueFunction are we creating tbe table for? 03698 INT32 index = (INT32)GetUniqueID(); 03699 index -= (INT32)ValueFunctionID_BevelEnds + 1; 03700 03701 03702 //Make the four control points of the Bezier... 03703 DocCoord p1; 03704 p1.x = 0; p1.y = INT32(Value1y*100000); 03705 DocCoord p2; 03706 p2.x = INT32(Value2x*100000); p2.y = INT32(Value2y*100000); 03707 DocCoord p3; 03708 p3.x = INT32(Value3x*100000); p3.y = INT32(Value3y*100000); 03709 DocCoord p4; 03710 p4.x = 100000; p4.y = INT32(Value4y*100000); 03711 03712 //Create the Bezier curve path denoted by the four control points 03713 Path strokePath; 03714 strokePath.Initialise(); 03715 strokePath.InsertMoveTo(p1, NULL); 03716 strokePath.InsertCurveTo(p2, p3, p4, NULL); 03717 03718 //Find out how long the path is... 03719 double pathlength = strokePath.GetPathLength(); 03720 DocCoord* pPoint = new DocCoord; 03721 03722 TRACEUSER( "Matt", _T("\nStarting to make Bezier table...\n")); 03723 for (INT32 counter = 0; counter < 256; counter++) 03724 { 03725 //At even intervals along the length of the curve, record the x and y coordinate 03726 MILLIPOINT Distance = (INT32(pathlength)/256)*counter; 03727 strokePath.GetPointAtDistance(Distance, pPoint, NULL, NULL); 03728 03729 xvalue[index][counter] = double(pPoint->x) / 100000.0; 03730 yvalue[index][counter] = double(pPoint->y) / 100000.0; 03731 03732 // TRACEUSER( "Matt", _T("xvalue[%d] = %f; yvalue[%d] = %f;\n"),counter,xvalue[counter],counter,yvalue[counter]); 03733 } 03734 TRACEUSER( "Matt", _T("Finished table...\n\n")); 03735 03736 delete pPoint; 03737 }