// $Id: fixed.cpp 1282 2006-06-09 09:46:49Z alex $ /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE ================================XARAHEADERSTART=========================== Xara LX, a vector drawing and manipulation program. Copyright (C) 1993-2006 Xara Group Ltd. Copyright on certain contributions may be held in joint with their respective authors. See AUTHORS file for details. LICENSE TO USE AND MODIFY SOFTWARE ---------------------------------- This file is part of Xara LX. Xara LX is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. Xara LX and its component source files are distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Xara LX (see the file GPL in the root directory of the distribution); if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ADDITIONAL RIGHTS ----------------- Conditional upon your continuing compliance with the GNU General Public License described above, Xara Group Ltd grants to you certain additional rights. The additional rights are to use, modify, and distribute the software together with the wxWidgets library, the wxXtra library, and the "CDraw" library and any other such library that any version of Xara LX relased by Xara Group Ltd requires in order to compile and execute, including the static linking of that library to XaraLX. In the case of the "CDraw" library, you may satisfy obligation under the GNU General Public License to provide source code by providing a binary copy of the library concerned and a copy of the license accompanying it. Nothing in this section restricts any of the rights you have under the GNU General Public License. SCOPE OF LICENSE ---------------- This license applies to this program (XaraLX) and its constituent source files only, and does not necessarily apply to other Xara products which may in part share the same code base, and are subject to their own licensing terms. This license does not apply to files in the wxXtra directory, which are built into a separate library, and are subject to the wxWindows license contained within that directory in the file "WXXTRA-LICENSE". This license does not apply to the binary libraries (if any) within the "libs" directory, which are subject to a separate license contained within that directory in the file "LIBS-LICENSE". ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS ---------------------------------------------- Subject to the terms of the GNU Public License (see above), you are free to do whatever you like with your modifications. However, you may (at your option) wish contribute them to Xara's source tree. You can find details of how to do this at: http://www.xaraxtreme.org/developers/ Prior to contributing your modifications, you will need to complete our contributor agreement. This can be found at: http://www.xaraxtreme.org/developers/contribute/ Please note that Xara will not accept modifications which modify any of the text between the start and end of this header (marked XARAHEADERSTART and XARAHEADEREND). MARKS ----- Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara designs are registered or unregistered trademarks, design-marks, and/or service marks of Xara Group Ltd. All rights in these marks are reserved. Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK. http://www.xara.com/ =================================XARAHEADEREND============================ */ // // Fixed-point primitive routines // #include "camtypes.h" //#include "fixed.h" - in camtypes.h [AUTOMATICALLY REMOVED] /******************************************************************************************** > FIXED16 Fixed16Mul(FIXED16 arg1, FIXED16 arg2) Author: Andy_Pennell (Xara Group Ltd) Created: 10/5/93 Inputs: two fixed16s Outputs: None Returns: FIXED16 result (arg1 * arg2) Scope: Only to be used in the FIXED16 class. Purpose: signed multiplication Errors: None (no overflow checks). Rounds ********************************************************************************************/ fixed16 Fixed16Mul(fixed16 a,fixed16 b) { fixed16 result ; // result.all = INT32(Int32x32To64(a.all,b.all)+0x8000>>16) ; result.all = INT32(((xlong)a.all*b.all+0x8000) >> 16) ; return result ; } /******************************************************************************************** > FIXED16 Fixed16Div(FIXED16 arg1, FIXED16 arg2) Author: Andy_Pennell (Xara Group Ltd) Created: 10/5/93 Inputs: two fixed16s Outputs: None Returns: FIXED16 result (arg1 / arg2) Scope: Only to be used in the FIXED16 class. Purpose: signed division Errors: None (no overflow checks). No rounding either (should it?) Overflow will cause a DIV0 exception, as will divide by zero ********************************************************************************************/ fixed16 Fixed16Div(fixed16 a,fixed16 b) { fixed16 result ; // result.all = MulDiv(a.all,1<<16,b.all) ; result.all = INT32(((xlong)a.all<<16)/b.all) ; return result ; } /******************************************************************************************** > NOTREALLYAFIXED16 InternalDiv32by32( INT32 arg1, INT32 arg2 ) Author: Andy_Pennell (Xara Group Ltd) Created: 11/5/93 Inputs: two signed 32-bit numbers Outputs: None Returns: FIXED16 result of arg1/arg2 Scope: Private to the CCMATHS library. Purpose: Obtain a fixed-point representation of the ratio between two signed numbers. Errors: None. Div0 and overflow will create a div0 exception. Awooga! Awooga! Do not call this function directly - it returns a INT32 and is meant to be used only in the C++ wrapper (i.e. it returns the value << 16) This is done by multiplying arg1 by 65536, then doing a 64-bit/32-bit division Curiously enough, this function is 100% the same as Fixed16Div. When you think about it, its not really that curious as both args are 65536 times bigger than the FIXED16 versions, and x/y is identical to x*65536/y*65536. ********************************************************************************************/ fixed16 InternalDiv32by32( INT32 a, INT32 b ) { fixed16 result ; // result.all = MulDiv(a.all,1<<16,b.all) ; result.all = INT32( ( (xlong)a << 16 ) / b ); return result ; } /******************************************************************************************** > double Fixed16ToDouble( FIXED16 arg ) Author: Andy_Pennell (Xara Group Ltd) Created: 13/5/93 Inputs: FIXED16 argument Outputs: None Returns: double-precision value Scope: Only to be used in the FIXED16 class. Purpose: General type conversion Errors: None This code relies on the compiler efficiently replacing the division by a multiplication of the reciprical. ********************************************************************************************/ double Fixed16ToDouble( fixed16 a ) { return (double)a.all/(1<<16) ; } /******************************************************************************************** > fixed16 DoubleToFixed16( double arg ) Author: Andy_Pennell (Xara Group Ltd) Created: 14/5/93 Inputs: double-precision argument Outputs: None Returns: FIXED16 value Purpose: General type conversion Errors: None (overflow will cause exception) This is done by taking the arg and multiplying it by 65536, then converting to integer. ********************************************************************************************/ fixed16 DoubleToFixed16( double arg ) { fixed16 result ; #if 0//defined(_M_IX86) // // This avoids the slow fix operation. Add a large number so that // the double always has the same exponent and the mantissa becomes, // in affect, a fixed point value with the value we want in the // bottom 32 bits. // // Note that we are relying on the compiler to convert this to // efficient code. // // TODO: Test! // static const double fFix = (XLONG)3<<(DBL_MANT_DIG-16-2); double F = arg+fFix; result.all = (INT32&)F ; #else result.all = INT32(arg*(1<<16)) ; #endif return result ; } /******************************************************************************************** > FIXED16 Fixed16Sin( FIXED16 arg ) Author: Andy_Pennell (Xara Group Ltd) Created: 13/5/93 Inputs: FIXED16 argument in degrees Outputs: None Returns: FIXED16 result Scope: Only to be used in the FIXED16 class. Purpose: General trigonometry Errors: None ********************************************************************************************/ /******************************************************************************************** > FIXED16 Fixed16Cos( FIXED16 arg ) Author: Andy_Pennell (Xara Group Ltd) Created: 13/5/93 Inputs: FIXED16 argument in degrees Outputs: None Returns: FIXED16 result Scope: Only to be used in the FIXED16 class. Purpose: General trigonometry Errors: None ********************************************************************************************/ // // If n is the input arg in degrees, then from a INT32 it is arg/65536. // In radians, this is arg/65536*pi/180 which is arg*pi/11796480 (=approx 2.66e-7) // The result then needs multiplying by 65536 before returning as a INT32. // fixed16 Fixed16Sin( fixed16 arg ) { return DoubleToFixed16( sin( double(2.6631610900792382460383465095346e-7) * arg.MakeDouble() ) ); } fixed16 Fixed16Cos( fixed16 arg ) { return DoubleToFixed16( cos( double(2.6631610900792382460383465095346e-7) * arg.MakeDouble() ) ); } /******************************************************************************************** > INT32 MatrixCalc( FIXED16 fix1, INT32 l1, FIXED16 fix2, INT32 l2) Author: Andy_Pennell (Xara Group Ltd) Created: 14/5/93 Inputs: two FIXED16s, two INT32s Outputs: None Returns: INT32 result of fix1*l1 + fix2*l2 Scope: Only to be used in the Matrix classes. Purpose: Matrix multiply primitive done using intermediate 64-bit results so accuracy is maintained. Special cases are when fix1 or fix2 are 0.0 or 1.0 as multiplications may be avoided. Note that the result is rounded to the nearest integer. Errors: None (overflow ignored). ********************************************************************************************/ INT32 MatrixCalc( fixed16 fix1, INT32 l1, fixed16 fix2, INT32 l2) { return INT32( ( (xlong)fix1.all * l1 + (xlong)fix2.all * l2 ) >> 16 ); } /******************************************************************************************** > INT32 LongMulFixed16( INT32 arg, FIXED16 fix ) Author: Andy_Pennell (Xara Group Ltd) Created: 14/5/93 Inputs: one FIXED16, one INT32 Outputs: None Returns: INT32 result of fix * arg Scope: Only to be used in the Matrix class. Purpose: Method of multiplying a INT32 by a fixed point number keeping as much accuracy as possible. Errors: None (overflow ignored). ********************************************************************************************/ INT32 LongMulFixed16( INT32 arg, fixed16 fix ) { return INT32( ((xlong)arg * fix.all + 0x8000) >> 16 ); } /******************************************************************************************** > INT32 LongDivFixed16( INT32 arg, FIXED16 fix ) Author: Andy_Pennell (Xara Group Ltd) Created: 13/7/93 Inputs: one FIXED16, one INT32 Outputs: None Returns: INT32 result of arg / fix Purpose: Method of dividing an INT32 by a fixed point number keeping as much accuracy as possible. Errors: None (overflow ignored). Div0 and Overflow will take exception. ********************************************************************************************/ INT32 LongDivFixed16( INT32 arg, fixed16 fix ) { return INT32(((xlong)arg<<16)/fix.all) ; } /******************************************************************************************** > INT32 MPtoPixel( INT32 arg, FIXED16 fix ) Author: Will_Cowling (Xara Group Ltd) Created: 14/9/93 Inputs: one FIXED16, one INT32 Outputs: None Returns: INT32 result of arg / fix Purpose: Method of dividing a INT32 by a fixed point number keeping as much accuracy as possible. This version will Round any fractional result to the NEAREST whole value. It is used for scaling Millipoints to Whole Pixels. Assumptions:Fix is +ve. Errors: None (overflow ignored). Div0 and Overflow will take exception. ********************************************************************************************/ INT32 MPtoPixel( INT32 arg, fixed16 fix ) { if ( arg<0 ) return INT32((((xlong)arg<<16)-(fix.all>>1))/fix.all) ; else return INT32((((xlong)arg<<16)+(fix.all>>1))/fix.all) ; // Gavin says (07/03/2006) the following would be more accurate so long as // we could guarantee that fix.all<<1 does not overflow: // if ( arg<0 ) // return INT32((((xlong)arg<<17)-fix.all))/(fix.all<<1)) ; // else // return INT32((((xlong)arg<<17)+fix.all))/(fix.all<<1)) ; } /******************************************************************************************** > INT32 MPtoOS256( INT32 arg, FIXED16 fix ) Author: Will_Cowling (Xara Group Ltd) Created: 14/9/93 Inputs: one FIXED16, one INT32 Outputs: None Returns: INT32 result of arg / fix Purpose: Method of dividing a INT32 by a fixed point number keeping as much accuracy as possible. This version will convert the MP value to 256ths of a Pixel. Errors: None (overflow ignored). Div0 and Overflow will take exception. ********************************************************************************************/ INT32 MPtoOS256( INT32 arg, fixed16 fix ) { return INT32(((xlong)arg<<24)/fix.all) ; }