Revision: 7978
http://armagetronad.svn.sourceforge.net/armagetronad/?rev=7978&view=rev
Author: philippeqc
Date: 2008-02-17 03:20:02 -0800 (Sun, 17 Feb 2008)
Log Message:
-----------
Added a marshaler object to tPolynomial to facilitate manipulation of item such as rotationAngle and rotationSpeed
Modified Paths:
--------------
armagetronad/trunk/armagetronad/src/tools/tPolynomial.h
armagetronad/trunk/armagetronad/src/tools/unitTest/Makefile
Added Paths:
-----------
armagetronad/trunk/armagetronad/src/tools/tPolynomial.cpp
armagetronad/trunk/armagetronad/src/tools/unitTest/tPolynomialMarshalerTest.cpp
Added: armagetronad/trunk/armagetronad/src/tools/tPolynomial.cpp
===================================================================
--- armagetronad/trunk/armagetronad/src/tools/tPolynomial.cpp (rev 0)
+++ armagetronad/trunk/armagetronad/src/tools/tPolynomial.cpp 2008-02-17 11:20:02 UTC (rev 7978)
@@ -0,0 +1,137 @@
+#include "tPolynomial.h"
+
+void tPolynomialMarshaler::parse(std::string str)
+{
+ int bPos;
+ if ( (bPos = str.find(';')) != -1)
+ {
+ parsePart(str.substr(0, bPos) , constants);
+ parsePart(str.substr(bPos + 1, str.length()), variants);
+ }
+ else
+ {
+ parsePart(str, constants);
+ variants.SetLen(0);
+ }
+}
+
+tPolynomialMarshaler::tPolynomialMarshaler()
+:constants(0),
+ variants(0)
+{
+ // Empty
+}
+
+tPolynomialMarshaler::tPolynomialMarshaler(std::string str)
+:constants(0),
+ variants(0)
+{
+ parse(str);
+}
+
+tPolynomialMarshaler::tPolynomialMarshaler(const tPolynomialMarshaler & other)
+:constants(other.constants),
+ variants(other.variants)
+{
+ // Empty
+}
+
+void tPolynomialMarshaler::setConstant(REAL value, int index)
+{
+ if(index >= constants.Len()) {
+ grow(constants, index+1);
+ }
+ constants[index] = value;
+}
+
+void tPolynomialMarshaler::setVariant(REAL value, int index)
+{
+ if(index >= variants.Len()) {
+ grow(variants, index+1);
+ }
+ variants[index] = value;
+}
+
+void tPolynomialMarshaler::parsePart(std::string str, tArray<REAL> &array)
+{
+ int pos;
+ int prevPos = 0;
+ int index = 0;
+
+ pos = str.find(':', 0);
+ if(-1 != pos) {
+ do{
+ REAL value = atof(str.substr(prevPos, pos).c_str());
+ array.SetLen(index + 2); // +1 because to write at index n, the len must be n+1. +1 to allocate a place for the element after the last ':'
+ array[index] = value;
+
+ prevPos = pos + 1;
+ index ++;
+ }
+ while ( (pos = str.find(':', prevPos)) != -1) ;
+
+ array[index] = atof(str.substr(prevPos, pos).c_str());
+
+ }
+ else {
+ array.SetLen(1);
+ array[0] = atof(str.c_str());
+ }
+}
+
+bool areArrayEqual (const tArray<REAL> & left, const tArray<REAL> & right)
+{
+ bool res = true;
+ if(left.Len() != right.Len())
+ res = false;
+
+ for(int i=0; i<left.Len(); i++) {
+ if(fabs(left[i] - right[i]) > DELTA)
+ res = false;
+ }
+
+ return res;
+}
+
+bool operator == (const tPolynomialMarshaler & left, const tPolynomialMarshaler & right)
+{
+ bool res = true;
+
+ res = areArrayEqual(left.constants, right.constants)
+ && areArrayEqual(left.variants, right.variants);
+
+ return res;
+}
+
+bool operator != (const tPolynomialMarshaler & left, const tPolynomialMarshaler & right)
+{
+ return !(left == right);
+}
+
+void tPolynomialMarshaler::grow(tArray<REAL> &array, int newLength)
+{
+ int oldLength = array.Len();
+ array.SetLen(newLength);
+ for(int i=oldLength; i<newLength; i++) {
+ array[i] = 0;
+ }
+}
+
+
+std::string tPolynomialMarshaler::toString()
+{
+ std::ostringstream ostr("");
+
+ ostr << "Constant len :" << constants.Len() << " ";
+ for(int i=0; i<constants.Len(); i++) {
+ ostr << " c[" << i << "]:" << constants[i];
+ }
+ ostr << std::endl;
+ ostr << "Variant len :" << variants.Len() << " ";
+ for(int i=0; i<variants.Len(); i++) {
+ ostr << " c[" << i << "]:" << variants[i];
+ }
+ ostr << std::endl;
+
+ return ostr.str();
+}
Modified: armagetronad/trunk/armagetronad/src/tools/tPolynomial.h
===================================================================
--- armagetronad/trunk/armagetronad/src/tools/tPolynomial.h 2008-02-17 11:17:57 UTC (rev 7977)
+++ armagetronad/trunk/armagetronad/src/tools/tPolynomial.h 2008-02-17 11:20:02 UTC (rev 7978)
@@ -32,8 +32,14 @@
#include <math.h>
#include "tArray.h"
+#include <iostream>
+#include <string>
+
#define REAL float
+#define MAX(a, b) ((a>b)?a:b)
+#define MIN(a, b) ((a<b)?a:b)
+
//! mathematical function (to be moved into tools sometime, and currently limited to linear functions)
template <typename T>
class tPolynomial
@@ -85,7 +91,7 @@
friend bool operator != (const tPolynomial<D> & left, const tPolynomial<D> & right);
virtual void toString() const;
- tPolynomial<T> clamp(REAL min, REAL max, REAL valueOfVariable);
+ tPolynomial<T> const clamp(REAL min, REAL max, REAL valueOfVariable);
int Len() const{
return coefs.Len();
@@ -101,6 +107,40 @@
tArray<REAL> coefs;
};
+/*! \brief Marshal a tPolynomial as an input value (var) for "a + b*var + (c + d*var)*t"
+ *
+ *
+ */
+class tPolynomialMarshaler
+{
+ public:
+ tPolynomialMarshaler(); //!< Default constructor
+ tPolynomialMarshaler(std::string str); //!< Parsing constructor
+ tPolynomialMarshaler(const tPolynomialMarshaler & other); //!< Copy constructor
+
+ void setConstant(REAL value, int index);
+ void setVariant(REAL value, int index);
+
+ void parse(std::string str);
+
+ template<typename D>
+ tPolynomial<D> const marshal(const tPolynomial<D> & other);
+
+ std::string toString();
+
+ friend bool operator == (const tPolynomialMarshaler & left, const tPolynomialMarshaler & right);
+ // template<typename D>
+ friend bool operator != (const tPolynomialMarshaler & left, const tPolynomialMarshaler & right);
+ protected:
+ void parsePart(std::string str, tArray<REAL> &array);
+ void grow(tArray<REAL> &array, int newSize); //!< grows and initialise to 0 the new elements for the passed array to the new length
+ int getLenConstant() const {return constants.Len();};
+ int getLenVariant()const {return variants.Len();};
+
+ tArray<REAL> constants;
+ tArray<REAL> variants;
+};
+
//These templates are probably only useable with nMessage as parameter.
//The reason they're templates is that nMessage isn't available in src/tools
//and that tPolynomial might be needed to be in src/tools in the future.
@@ -248,8 +288,8 @@
// If the length of the coefs array differ, then the extra elements should be 0
- int maxLength = left.coefs.Len()>right.coefs.Len()?left.coefs.Len():right.coefs.Len();
- int minLength = left.coefs.Len()<right.coefs.Len()?left.coefs.Len():right.coefs.Len();
+ int maxLength = MAX(left.coefs.Len(), right.coefs.Len());
+ int minLength = MIN(left.coefs.Len(), right.coefs.Len());
bool res = true;
@@ -471,16 +511,12 @@
// Bring the polynomial to the same baseValue, so that the terms mean the same thing
tPolynomial<T> tRebasedRight(tfRight.evaluateCoefsAt(this->baseValueOfVariable));
- int maxLength = this->coefs.Len()>tfRight.coefs.Len()?this->coefs.Len():tfRight.coefs.Len();
- int minLength = this->coefs.Len()<tfRight.coefs.Len()?this->coefs.Len():tfRight.coefs.Len();
+ int maxLength = MAX(this->coefs.Len(), tfRight.coefs.Len());
// Set the lenght to the longest member of the addition
tRebasedRight.coefs.SetLen(maxLength);
- for (int i=tfRight.Len(); i<maxLength; i++) {
- tRebasedRight[i] = 0.0;
- }
- for (int i=0; i<minLength; i++) {
+ for (int i=0; i<this->coefs.Len(); i++) {
tRebasedRight[i] += coefs[i];
}
@@ -492,7 +528,7 @@
// Bring the polynomial to the same baseValue, so that the terms mean the same thing
tPolynomial<T> tRebasedRight = tfRight.evaluateCoefsAt(this->baseValueOfVariable);
- int maxLength = this->coefs.Len()>tfRight.coefs.Len()?this->coefs.Len():tfRight.coefs.Len();
+ int maxLength = MAX(this->coefs.Len(), tfRight.coefs.Len());
// Set the lenght to the longest member of the addition
coefs.SetLen(maxLength);
@@ -546,7 +582,7 @@
* Otherwise, return a new polynomial that is bound by the range
*/
template <typename T>
-tPolynomial<T> tPolynomial<T>::clamp(REAL minValue, REAL maxValue, REAL valueOfVariable)
+tPolynomial<T> const tPolynomial<T>::clamp(REAL minValue, REAL maxValue, REAL valueOfVariable)
{
tPolynomial<T> tf(*this);
@@ -571,5 +607,59 @@
return tf;
}
+
+// *******************************************************
+// *******************************************************
+// *******************************************************
+// *******************************************************
+
+bool operator == (const tPolynomialMarshaler & left, const tPolynomialMarshaler & right);
+bool operator != (const tPolynomialMarshaler & left, const tPolynomialMarshaler & right);
+
+// *******************************************************
+// *******************************************************
+// *******************************************************
+// *******************************************************
+
+template<typename D>
+tPolynomial<D> const tPolynomialMarshaler::marshal(const tPolynomial<D> & other)
+{
+ tPolynomial<D> tf(0);
+ tPolynomial<D> res(0);
+
+ for(int i=variants.Len()-1; i>0; i--) {
+ tf = (tf + variants[i]) * other;
+ }
+ if(0 != variants.Len()) {
+ tf = tf + variants[0];
+ }
+
+ {
+ REAL tData[] = {0.0, 1.0};
+ tPolynomial<D> t(tData, sizeof(tData)/sizeof(tData[0]));
+
+ res = tf * t;
+ }
+
+ // Reset tf for further computation
+ tf = tPolynomial<D>(0);
+
+ for(int i=constants.Len()-1; i>0; i--) {
+ tf = (tf + constants[i]) * other;
+ }
+ if(0 != constants.Len()) {
+ tf = tf + constants[0];
+ }
+
+ res += tf;
+
+
+ return res;
+}
+
+
+
+
+
#endif
Modified: armagetronad/trunk/armagetronad/src/tools/unitTest/Makefile
===================================================================
--- armagetronad/trunk/armagetronad/src/tools/unitTest/Makefile 2008-02-17 11:17:57 UTC (rev 7977)
+++ armagetronad/trunk/armagetronad/src/tools/unitTest/Makefile 2008-02-17 11:20:02 UTC (rev 7978)
@@ -2,11 +2,12 @@
CC=g++
CFLAGS=-ggdb -Wall -I.. -I../.. -I../../network -I../../../bin
LDFLAGS= -L/usr/lib/ -lcppunit
-EXTRA_SOURCES=../tArray.cpp ../tError.cpp
-SOURCES=tPolynomialTest.cpp tToolUnitTest.cpp nMessageMock.cpp $(EXTRA_SOURCES)
-HEADERS=tPolynomial.h tPolynomialWithBase.hOB
-EXPERIMENTATION=myTArray
-EXPERIMENTATION_SRC=myTArray.cpp
+EXTRA_SOURCES=../tArray.cpp ../tError.cpp ../tPolynomial.cpp
+SOURCES=tPolynomialTest.cpp tPolynomialMarshalerTest.cpp tToolUnitTest.cpp nMessageMock.cpp $(EXTRA_SOURCES)
+#SOURCES=tPolynomialMarshalerTest.cpp tToolUnitTest.cpp nMessageMock.cpp $(EXTRA_SOURCES)
+HEADERS=tPolynomial.h tPolynomialWithBase.h
+EXPERIMENTATION=
+EXPERIMENTATION_SRC=
EXPERIMENTATION_OBJECTS=$(EXPERIMENTATION_SRC:.cpp=.o)
OBJECTS=$(SOURCES:.cpp=.o)
EXTRA_OBJECTS=$(EXTRA_SOURCES:.cpp=.o)
@@ -20,6 +21,10 @@
$(EXPERIMENTATION): $(EXPERIMENTATION_SRC) $(EXTRA_SOURCES)
$(CC) $(CFLAGS) -c $(EXPERIMENTATION_SRC)
$(CC) $(LDFLAGS) $(EXPERIMENTATION_OBJECTS) $(EXTRA_OBJECTS) -o $@
-
+
.cpp.o: $(HEADERS)
$(CC) $(CFLAGS) -c $< -o $@
+
+clean:
+ rm *o
+ rm $(EXECUTABLE)
Added: armagetronad/trunk/armagetronad/src/tools/unitTest/tPolynomialMarshalerTest.cpp
===================================================================
--- armagetronad/trunk/armagetronad/src/tools/unitTest/tPolynomialMarshalerTest.cpp (rev 0)
+++ armagetronad/trunk/armagetronad/src/tools/unitTest/tPolynomialMarshalerTest.cpp 2008-02-17 11:20:02 UTC (rev 7978)
@@ -0,0 +1,184 @@
+#include "nMessageMock.h"
+#include "tPolynomial.h"
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+
+class tPolynomialMarshalerTest : public CppUnit::TestFixture {
+private:
+ tPolynomialMarshaler marshalerA;
+ tPolynomialMarshaler marshalerB;
+ tPolynomialMarshaler marshalerC;
+
+ std::string dataInA;
+ std::string dataInB;
+ std::string dataInC;
+
+public:
+ CPPUNIT_TEST_SUITE( tPolynomialMarshalerTest );
+ CPPUNIT_TEST( testParsing );
+ CPPUNIT_TEST( testConstructor );
+ CPPUNIT_TEST( testMarshaling );
+ CPPUNIT_TEST_SUITE_END();
+
+public:
+ void setUp() {
+ dataInA = "3;5";
+ dataInB = "3:5;7:9";
+ dataInC = "1:2:3;4:5:6";
+ // populate marshaler C to :
+ // constant = {3.0}
+ // variant = {5.0}
+ marshalerA.setConstant(3.0, 0);
+ marshalerA.setVariant(5.0, 0);
+
+ // populate marshaler C to :
+ // constant = {3.0, 5.0}
+ // variant = {7.0, 9.0}
+ marshalerB.setConstant(3.0, 0);
+ marshalerB.setConstant(5.0, 1);
+ marshalerB.setVariant(7.0, 0);
+ marshalerB.setVariant(9.0, 1);
+
+ // populate marshaler C to :
+ // constant = {1.0, 2.0, 3.0}
+ // variant = {4.0, 5.0, 6.0}
+ marshalerC.setConstant(1.0, 0);
+ marshalerC.setConstant(2.0, 1);
+ marshalerC.setConstant(3.0, 2);
+ marshalerC.setVariant(4.0, 0);
+ marshalerC.setVariant(5.0, 1);
+ marshalerC.setVariant(6.0, 2);
+ }
+
+ void tearDown() {
+ // Empty
+ }
+
+ void testParsing() {
+ tPolynomialMarshaler marshalerParsed;
+
+ marshalerParsed.parse(dataInB);
+ CPPUNIT_ASSERT( marshalerB == marshalerParsed );
+
+ marshalerParsed.parse(dataInA);
+ CPPUNIT_ASSERT( marshalerA == marshalerParsed );
+
+ marshalerParsed.parse(dataInC);
+ CPPUNIT_ASSERT( marshalerC == marshalerParsed );
+ }
+
+ void testConstructor() {
+ // copy constructor
+ tPolynomialMarshaler marshalerCopyA(marshalerA);
+ CPPUNIT_ASSERT( marshalerA == marshalerCopyA );
+ tPolynomialMarshaler marshalerCopyB(marshalerB);
+ CPPUNIT_ASSERT( marshalerB == marshalerCopyB );
+ tPolynomialMarshaler marshalerCopyC(marshalerC);
+ CPPUNIT_ASSERT( marshalerC == marshalerCopyC );
+
+ // parsing constructor
+ tPolynomialMarshaler marshalerParsedA(dataInA);
+ CPPUNIT_ASSERT( marshalerA == marshalerParsedA );
+ tPolynomialMarshaler marshalerParsedB(dataInB);
+ CPPUNIT_ASSERT( marshalerB == marshalerParsedB );
+ tPolynomialMarshaler marshalerParsedC(dataInC);
+ CPPUNIT_ASSERT( marshalerC == marshalerParsedC );
+ }
+
+ void testMarshaling() {
+ /*
+ * the polynomial {7, 5, 3} (here noted as x) will be marshaled as:
+ * a + b*x + c*x^2 + t * (d + e*x + f*x^2)
+ *
+ * For the case A:
+ * a=3, d=5, b=c=e=f=0
+ * should produce:
+ * a + b*x + c*x^2 + t * (d + e*x + f*x^2)
+ * a + t * (d)
+ * 3 + 5t
+ *
+ * For the case B:
+ * a=3, b=5, d=7, e=9, c=f=0
+ * should produce:
+ * a + b*x + c*x^2 + t * (d + e*x + f*x^2)
+ * a + b*x + t * (d + e*x)
+ * 3 + 5*x + t * (7 + 9*x)
+ * 3 + 5*{7, 5, 3} + t * (7 + 9*{7, 5, 3})
+ * 3 + {35, 25, 15t} + t * (7 + {63, 45, 27})
+ * 3 + (35 + 25*t +15*t^2) + t * (7 + 63 + 45*t + 27*t^2})
+ * 38 + 25*t +15*t^2 + t * (70 + 45*t + 27*t^2})
+ * 38 + 25*t +15*t^2 + 70*t + 45*t^2 + 27*t^3
+ * 38 + 95*t + 60*t^2 + 27*t^3
+ *
+ * For the case C:
+ * where a=1, b=2, c=3, d=4, e=5, f=6
+ * should produce:
+ * a + b*x + c*x^2 + t * (d + e*x + f*x^2)
+ * 1 + 2*x + 3*x^2 + t * (4 + 5*x + 6*x^2)
+ * 1 + 2*{7, 5, 3} + 3*{7, 5, 3}^2 + t * (4 + 5*{7, 5, 3} + 6*{7, 5, 3}^2)
+ * nota: {7, 5, 3}^2 => {49, 70, 67, 30, 9}
+ * 1 + 2*{7, 5, 3} + 3*{49, 70, 67, 30, 9} + t * (4 + 5*{7, 5, 3} + 6*{49, 70, 67, 30, 9})
+ * 1 + {14, 10, 6} + {147, 210, 201, 90, 27} + t * (4 + {35, 25, 15} + {294, 420, 402, 180, 54})
+ * 1 + 14 + 10*t + 6*t^2 + 147 + 210*t + 201*t^2 + 90*t^3 + 27*t^4 + t * (4 + 35 + 25*t + 15*t^2 + 294 + 420*t + 402*t^2 + 180*t^3 + 54*t^4)
+ * 162 + 220*t + 207*t^2 + 90*t^3 + 27*t^4 + t * (333 + 445*t + 417*t^2 + 180*t^3 + 54*t^4)
+ * 162 + 220*t + 207*t^2 + 90*t^3 + 27*t^4 + 333*t + 445*t^2 + 417*t^3 + 180*t^4 + 54*t^5
+ * 162 + 553*t + 652*t^2 + 507*t^3 + 207*t^4 + 54*t^5
+ *
+ */
+ float inputData[] = {7, 5, 3};
+ float expectedDataA[] = {3, 5};
+ float expectedDataB[] = {38, 95, 60, 27};
+ float expectedDataC[] = {162, 553, 652, 507, 207, 54};
+ tPolynomial<nMessageMock> inputPolynomial(inputData, sizeof(inputData)/sizeof(inputData[0]));
+ tPolynomial<nMessageMock> expectedA(expectedDataA, sizeof(expectedDataA)/sizeof(expectedDataA[0]));
+ tPolynomial<nMessageMock> expectedB(expectedDataB, sizeof(expectedDataB)/sizeof(expectedDataB[0]));
+ tPolynomial<nMessageMock> expectedC(expectedDataC, sizeof(expectedDataC)/sizeof(expectedDataC[0]));
+
+ float tData[] = {0, 1};
+ tPolynomial<nMessageMock> t( tData, 2 );
+
+ /*
+ // Similar to B
+ tPolynomial<nMessageMock> out2 =
+ inputPolynomial*5
+ + 3
+ + t * (
+ inputPolynomial*9
+ + 7
+ );
+
+ std::cout << std::endl;
+ std::cout << "manually generated expected output for case B : " << std::endl;
+ out2.toString();
+ std::cout << "marshaled output for case B : " << std::endl;
+ marshalerB.marshal(inputPolynomial).toString();
+ */
+
+ /*
+ // Similar to C
+ tPolynomial<nMessageMock> out3 =
+ inputPolynomial*inputPolynomial*3
+ + inputPolynomial*2
+ + 1
+ + t * (
+ inputPolynomial*inputPolynomial*6
+ + inputPolynomial*5
+ + 4
+ );
+
+
+ std::cout << std::endl;
+ std::cout << "manually generated expected output for case C : " << std::endl;
+ out3.toString();
+ std::cout << "marshaled output for case C : " << std::endl;
+ marshalerC.marshal(inputPolynomial).toString();
+ */
+
+ CPPUNIT_ASSERT ( expectedA == marshalerA.marshal(inputPolynomial) );
+ CPPUNIT_ASSERT ( expectedB == marshalerB.marshal(inputPolynomial) );
+ CPPUNIT_ASSERT ( expectedC == marshalerC.marshal(inputPolynomial) );
+ }
+
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION( tPolynomialMarshalerTest );
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|