OpenWalnut  1.4.0
WLine_test.h
1 //---------------------------------------------------------------------------
2 //
3 // Project: OpenWalnut ( http://www.openwalnut.org )
4 //
5 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
6 // For more information see http://www.openwalnut.org/copying
7 //
8 // This file is part of OpenWalnut.
9 //
10 // OpenWalnut is free software: you can redistribute it and/or modify
11 // it under the terms of the GNU Lesser General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // OpenWalnut is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public License
21 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
22 //
23 //---------------------------------------------------------------------------
24 
25 #ifndef WLINE_TEST_H
26 #define WLINE_TEST_H
27 
28 #include <sstream>
29 #include <string>
30 
31 #include <cxxtest/TestSuite.h>
32 
33 #include "../../exceptions/WOutOfBounds.h"
34 #include "../../WLimits.h"
35 #include "../WLine.h"
36 #include "WLineTraits.h"
37 #include "WPositionTraits.h"
38 
39 /**
40  * Unit tests the WLine class
41  */
42 class WLineTest : public CxxTest::TestSuite
43 {
44 public:
45  /**
46  * If two lines have different lengths they are considered diffrent
47  * regardless on the given delta and the first point on which they
48  * differ should be returned.
49  */
51  {
52  WLine line;
53  line.push_back( WPosition( 0, 0, 0 ) );
54  line.push_back( WPosition( 1, 0, 0 ) );
55  WLine other;
56  other.push_back( WPosition( 0, 0, 0 ) );
57  TS_ASSERT_EQUALS( equalsDelta( line, other, 0.0 ), 1 );
58  }
59 
60  /**
61  * If both lines are of same size, but there is a point differing on
62  * more than the given delta the first point which differs should be
63  * returned.
64  */
66  {
67  WLine line;
68  line.push_back( WPosition( 0, 0, 0 ) );
69  line.push_back( WPosition( 1, 0, 0 ) );
70  WLine other;
71  other.push_back( WPosition( 0, 0, 0 ) );
72  other.push_back( WPosition( 1, 0, 0 + 2 * wlimits::DBL_EPS ) );
73  TS_ASSERT_EQUALS( equalsDelta( line, other, wlimits::DBL_EPS ), 1 );
74  }
75 
76  /**
77  * If both lines are of same size and every point pair don't differ in
78  * terms of the given delta, -1 should be returned.
79  */
81  {
82  WLine line;
83  line.push_back( WPosition( 0, 0, 0 ) );
84  line.push_back( WPosition( 1, 0, 0 ) );
85  WLine other;
86  other.push_back( WPosition( 0, 0, 0 ) );
87  other.push_back( WPosition( 1, 0, 0 + 2 * wlimits::DBL_EPS ) );
88  TS_ASSERT_EQUALS( equalsDelta( line, other, 2 * wlimits::DBL_EPS ), -1 );
89  }
90 
91  /**
92  * When printing a line to stdout it the output should be as follows:
93  * [first_pos, ..., last_pos] where the positions also should be in
94  * the same format, so in the end we would have:
95  * [[0,1,0],...[0,0,0]]
96  */
97  void testOutputOperator( void )
98  {
99  WLine l;
100  l.push_back( WPosition( 1.0, 1.0, 3.1415 ) );
101  l.push_back( WPosition( 0.0, 0.0, 0.44 ) );
102  l.push_back( WPosition( 1.0, 1.0, 1.0 ) );
103  std::string expected( "[1.0000000000000000e+00;1.0000000000000000e+00;3.1415000000000002e+00;, "
104  "0.0000000000000000e+00;0.0000000000000000e+00;4.4000000000000000e-01;, "
105  "1.0000000000000000e+00;1.0000000000000000e+00;1.0000000000000000e+00;]" );
106  std::stringstream ss;
107  ss << l;
108  TS_ASSERT_EQUALS( expected, ss.str() );
109  }
110 
111  /**
112  * Two Lines are equal if they have the same points in the same order.
113  */
114  void testEqualityOperator( void )
115  {
116  WLine line1;
117  line1.push_back( WPosition( 1.0, 1.0, 3.1415 ) );
118  line1.push_back( WPosition( 0.0, 0.0, 0.44 ) );
119  line1.push_back( WPosition( 1.0, 1.0, 1.0 ) );
120  WLine line2;
121  line2.push_back( WPosition( 1.0, 1.0, 3.1415 ) );
122  line2.push_back( WPosition( 0.0, 0.0, 0.44 ) );
123  line2.push_back( WPosition( 1.0, 1.0, 1.0 ) );
124  TS_ASSERT_EQUALS( line1, line2 );
125  line2.back()[1] += 0.0000000001;
126  TS_ASSERT_DIFFERS( line1, line2 );
127  }
128 
129  /**
130  * When accessing an item within 0..length-1 a const reference to the
131  * WPosition object should be returned.
132  */
134  {
135  WLine line;
136  line.push_back( WPosition( 1.0, 1.0, 3.1415 ) );
137  line.push_back( WPosition( 0.0, 0.0, 0.44 ) );
138  line.push_back( WPosition( 1.0, 1.0, 1.0 ) );
139  WPosition expected( 1.0, 1.0, 1.0 );
140  TS_ASSERT_EQUALS( expected, line[2] );
141  }
142 
143  /**
144  * If for example the start and end points of two lines are in opposite
145  * direction we may want to change its direction.
146  */
147  void testReverseOrdering( void )
148  {
149  WLine line;
150  line.push_back( WPosition( 1, 2, 3 ) );
151  line.push_back( WPosition( 4, 5, 6 ) );
152  line.push_back( WPosition( 7, 8, 9 ) );
153  WLine expected;
154  expected.push_back( WPosition( 7, 8, 9 ) );
155  expected.push_back( WPosition( 4, 5, 6 ) );
156  expected.push_back( WPosition( 1, 2, 3 ) );
157  line.reverseOrder();
158  TS_ASSERT_EQUALS( line, expected );
159  }
160 
161  /**
162  * The path length of the line is the accumulated path lengths of all
163  * segements (point to point) in that line.
164  */
165  void testPathLength( void )
166  {
167  WLine line;
168  line.push_back( WPosition( 1, 2, 3 ) );
169  line.push_back( WPosition( 4, 5, 6 ) );
170  line.push_back( WPosition( 7, 8, 9 ) );
171  double expected = length( WPosition( 1, 2, 3 ) - WPosition( 4, 5, 6 ) ) +
172  length( WPosition( 4, 5, 6 ) - WPosition( 7, 8, 9 ) );
173  TS_ASSERT_DELTA( expected, pathLength( line ), 1e-6 );
174  }
175 
176  /**
177  * When resampling a line a new line is generated having the given number
178  * of sampling points. Its start and end points remain the same, but its
179  * curvature may change a bit and also its length!
180  * Down sampling means you will have
181  */
182  void testDownSampleLine( void )
183  {
184  WLine line;
185  line.push_back( WPosition( 0, 0, 0 ) );
186  line.push_back( WPosition( 1, 1, 0 ) );
187  line.push_back( WPosition( 2, 0, 0 ) );
188  line.push_back( WPosition( 3, 1, 0 ) );
189  line.resampleByNumberOfPoints( 3 );
190  WLine expected;
191  expected.push_back( WPosition( 0, 0, 0 ) );
192  expected.push_back( WPosition( 1.5, 0.5, 0 ) );
193  expected.push_back( WPosition( 3, 1, 0 ) );
194  assert_equals_delta( line, expected, 2 * wlimits::DBL_EPS );
195  }
196 
197  /**
198  * If the resampling rate of a line has as many points as the original line,
199  * no sampling should be applied.
200  */
202  {
203  WLine line;
204  for( size_t i = 0; i < 10; ++i )
205  {
206  line.push_back( WPosition( i, 3 * i, 10 - i ) );
207  }
208  TS_ASSERT( line.size() == 10 );
209  WLine expected( line ); // make a copy of the original
210  line.resampleByNumberOfPoints( 10 );
211  assert_equals_delta( line, expected );
212  }
213 
214  /**
215  * If the points are exactly in between of a segement nothing should fail.
216  */
218  {
219  WLine line;
220  WLine expected;
221  for( int i = 0; i < 3; ++i )
222  {
223  line.push_back( WPosition( i, std::pow( -1.0, i % 2 ), 0 ) );
224  expected.push_back( WPosition( i, std::pow( -1.0, i % 2 ), 0 ) );
225  expected.push_back( WPosition( i + 0.5, 0, 0 ) );
226  }
227  expected.pop_back();
228  line.resampleByNumberOfPoints( 5 );
229  assert_equals_delta( expected, line );
230  }
231 
232  /**
233  * When resampling with many sample points the numerical errors may sum
234  * up. Hence I watch if it not breaks a certain threshold: 1.0e-10*newSegmentLength.
235  */
237  {
238  WLine line;
239  WLine expected;
240  for( int i = 0; i < 100; ++i )
241  {
242  line.push_back( WPosition( i, std::pow( -1.0, i % 2 ), 0 ) );
243  expected.push_back( WPosition( i, std::pow( -1.0, i % 2 ), 0 ) );
244  expected.push_back( WPosition( i + 0.25, std::pow( -1.0, i % 2 ) * 0.5, 0 ) );
245  expected.push_back( WPosition( i + 0.5, 0, 0 ) );
246  expected.push_back( WPosition( i + 0.75, std::pow( -1.0, ( i + 1 ) % 2 ) * 0.5, 0 ) );
247  }
248  expected.pop_back();
249  expected.pop_back();
250  expected.pop_back();
251  line.resampleByNumberOfPoints( 4 * 99 + 1 );
252  assert_equals_delta( expected, line, 1.0e-10 * std::sqrt( 5.0 ) / 4 );
253  }
254 
255  /**
256  * If there are many new sample points between two old sample points nothing should fail either.
257  */
259  {
260  WLine line;
261  line.push_back( WPosition( 0, 0, 0 ) );
262  line.push_back( WPosition( 1, 1, 0 ) );
263  line.resampleByNumberOfPoints( 1001 );
264  WLine expected;
265  expected.push_back( WPosition( 0, 0, 0 ) );
266  for( size_t i = 1; i < 1001; ++i )
267  {
268  expected.push_back( WPosition( i / 1000.0, i / 1000.0, 0 ) );
269  }
270  assert_equals_delta( expected, line, 1.0 / 1001.0 * 1.0e-10 );
271  }
272 
273  /**
274  * The mid point of a WLine is just the point in the middle of the line.
275  * For lines with even numbered size the element before that non existing
276  * midPoint is selected.
277  */
279  {
280  WLine line;
281  line.push_back( WPosition( 0, 0, 0 ) );
282  line.push_back( WPosition( 1, 1, 0 ) );
283  line.push_back( WPosition( 2, 0, 0 ) );
284  line.push_back( WPosition( 3, 1, 0 ) );
285  WPosition expected( 1, 1, 0 );
286  TS_ASSERT_EQUALS( expected, WPosition( midPoint( line ) ) );
287  }
288 
289  /**
290  * When a line has uneven numbered size, the mid point is unique.
291  */
293  {
294  WLine line;
295  line.push_back( WPosition( 0, 0, 0 ) );
296  line.push_back( WPosition( 1, 1, 0 ) );
297  line.push_back( WPosition( 2, 0, 0 ) );
298  WPosition expected( 1, 1, 0 );
299  TS_ASSERT_EQUALS( expected, WPosition( midPoint( line ) ) );
300  }
301 
302  /**
303  * When calling midPoint on empty lines => there is no point to return
304  * hence an exception is generated.
305  */
307  {
308  WLine line;
309  WPosition expected( 1, 1, 0 );
310  TS_ASSERT_THROWS_EQUALS( midPoint( line ), WOutOfBounds &e, std::string( e.what() ), "There is no midpoint for an empty line." );
311  }
312 
313  /**
314  * The max segemnent length is the maximum length over all segments (p_i<->p_j). For further
315  * information look just on the name of the test function, I think this is really precised ;).
316  * (Ha one more line in hg churn!)
317  * BTW: If there are multiple max lengths (equidistant sampled tracts) the first shall be
318  * chosen, BTW: this is totally stupid!, if they are equals it doesn't matter anyway, huh???
319  */
321  {
322  WLine line;
323  line.push_back( WPosition( 0, 0, 0 ) );
324  line.push_back( WPosition( 1, 1, 0 ) );
325  line.push_back( WPosition( 2, 0, 0 ) );
326  TS_ASSERT_DELTA( maxSegmentLength( line ), std::sqrt( 2.0 ), wlimits::DBL_EPS );
327  line.push_back( WPosition( 0, 0, 0 ) );
328  TS_ASSERT_DELTA( maxSegmentLength( line ), 2.0, wlimits::DBL_EPS );
329  }
330 
331  /**
332  * If there no points at all, 0.0 shall be returned.
333  */
335  {
336  WLine line;
337  TS_ASSERT_EQUALS( maxSegmentLength( line ), 0.0 );
338  line.push_back( WPosition( 0, 3.1415, 0 ) );
339  TS_ASSERT_EQUALS( maxSegmentLength( line ), 0.0 );
340  }
341 
342  /**
343  * If there are duplicates next to each other => collapse them.
344  */
346  {
347  WLine line;
348  line.push_back( WPosition( 0.1, 3.4, 34254.5 ) );
349  line.push_back( WPosition( 0.1, 3.4, 34254.5 ) );
350  line.push_back( WPosition( 0.1, 3.4, 34254.5 ) );
351  line.push_back( WPosition( 0.1, 3.4, 34254.5 ) );
352  line.push_back( WPosition( 0.0, 0.0, 0.0 ) );
353  line.push_back( WPosition( 0.1, 3.4, 34254.5 ) );
354  line.push_back( WPosition( 0.1, 3.4, 34254.5 ) );
355  line.push_back( WPosition( 0.1, 3.4, 34254.5 ) );
356  WLine expected;
357  expected.push_back( WPosition( 0.1, 3.4, 34254.5 ) );
358  expected.push_back( WPosition( 0.0, 0.0, 0.0 ) );
359  expected.push_back( WPosition( 0.1, 3.4, 34254.5 ) );
361  assert_equals_delta( line, expected );
362  }
363 
364  /**
365  * No sample points should remain no sample points.
366  */
368  {
369  WLine line;
370  line.resampleBySegmentLength( 3.1415f );
371  assert_equals_delta( line, WLine() );
372  }
373 
374  /**
375  * Lines with size() == 1, should also remain untouched.
376  */
378  {
379  WLine line;
380  line.push_back( WPosition( 0.1, 3.4, 34254.5 ) );
381  WLine expected( line );
382  line.resampleBySegmentLength( 3.1415f );
383  assert_equals_delta( line, expected );
384  }
385 
386  /**
387  * If there is a segement bigger than the newSegmentLength, then the new segment should be
388  * inserted and then with the new point should be proceeded just the same.
389  */
391  {
392  WLine line;
393  line.push_back( WPosition( 0.0, 0.0, 0.0 ) );
394  line.push_back( WPosition( 1.1, 0.0, 0.0 ) );
395  line.resampleBySegmentLength( 1.0 );
396  WLine expected;
397  expected.push_back( WPosition( 0.0, 0.0, 0.0 ) );
398  expected.push_back( WPosition( 1.0, 0.0, 0.0 ) );
399  assert_equals_delta( line, expected );
400  }
401 
402  /**
403  * Only if a sample point comes out of the circle with radius newSegmentLength then append the
404  * point of intersection.
405  */
407  {
408  WLine line;
409  line.push_back( WPosition( 0.0, 0.0, 0.0 ) );
410  line.push_back( WPosition( 1.0, 1.0, 0.0 ) );
411  line.push_back( WPosition( 0.0, 1.0, 0.0 ) );
412  line.push_back( WPosition( 1.0, 2.0, 0.0 ) );
413  line.push_back( WPosition( 0.0, 2.0, 0.0 ) );
414  line.push_back( WPosition( 1.0, 3.0, 0.0 ) );
415  line.resampleBySegmentLength( 3.0 );
416  WLine expected;
417  expected.push_back( WPosition( 0.0, 0.0, 0.0 ) );
418  expected.push_back( WPosition( 0.870829, 2.87083, 0.0 ) );
419  assert_equals_delta( line, expected, 0.00001 );
420  }
421 
422 private:
423  /**
424  * TS_ASSERT_DELTA needs the operator+, operator- and operator< to be implemented especially for WPositions the operator< and operator +
425  * makes not really sense. Hence I implemented an assert by my one, giving reasonable out put.
426  *
427  * \param first First line to compare with
428  * \param second Second line to compare with
429  * \param delta The delta within two points are considered as equally
430  */
431  void assert_equals_delta( const WLine& first, const WLine& second, double delta = wlimits::DBL_EPS ) const
432  {
433  int diffPos = 0;
434  if( ( diffPos = equalsDelta( first, second, delta ) ) != -1 )
435  {
436  using string_utils::operator<<;
437  std::stringstream msg;
438  msg << "Lines are different in at least point: " << diffPos;
439  TS_FAIL( msg.str() );
440  if( static_cast< int >( first.size() ) > diffPos && static_cast< int >( second.size() ) > diffPos )
441  {
442  std::cout << "first line at: " << diffPos << std::endl << first[diffPos] << std::endl;
443  std::cout << "second line at: " << diffPos << std::endl << second[diffPos] << std::endl;
444  }
445  else
446  {
447  std::cout << "lines does not have the same number of points: first=" << first.size() << " second=" << second.size() << std::endl;
448  }
449  std::cout << "first line: " << std::endl << first << std::endl;
450  std::cout << "second line: " << std::endl << second << std::endl;
451  }
452  }
453 };
454 #endif // WLINE_TEST_H
A line is an ordered sequence of WPositions.
Definition: WLine.h:41
void testOutputOperator(void)
When printing a line to stdout it the output should be as follows: [first_pos, ..., last_pos] where the positions also should be in the same format, so in the end we would have: [[0,1,0],...[0,0,0]].
Definition: WLine_test.h:97
void testDownSampleLine(void)
When resampling a line a new line is generated having the given number of sampling points...
Definition: WLine_test.h:182
void testNumericalStabilityOfResampling(void)
When resampling with many sample points the numerical errors may sum up.
Definition: WLine_test.h:236
void testSamplingPointsAreExactlyInTheOldSegmentCenterAndCorners(void)
If the points are exactly in between of a segement nothing should fail.
Definition: WLine_test.h:217
void push_back(const value_type &value)
Wrapper around std::vector member function.
Definition: WMixinVector.h:457
void testReverseOrdering(void)
If for example the start and end points of two lines are in opposite direction we may want to change ...
Definition: WLine_test.h:147
void testSamplingWithSameNumberOfPoints(void)
If the resampling rate of a line has as many points as the original line, no sampling should be appli...
Definition: WLine_test.h:201
void testMidPointOnUnevenSize(void)
When a line has uneven numbered size, the mid point is unique.
Definition: WLine_test.h:292
void testEqualsDeltaOnDifferentLinesButWithinDelta(void)
If both lines are of same size and every point pair don't differ in terms of the given delta...
Definition: WLine_test.h:80
void resampleByNumberOfPoints(size_t numPoints)
Resample this line so it has a number of given points afterwards.
Definition: WLine.cpp:78
void resampleBySegmentLength(double newSegementLength)
Resample this line so there are only segements of the given length.
Definition: WLine.cpp:147
void testMaxSegementLength(void)
The max segemnent length is the maximum length over all segments (p_i<->p_j).
Definition: WLine_test.h:320
void removeAdjacentDuplicates()
Collapse samplepoints which are equal and neighboured.
Definition: WLine.cpp:124
void testResamplingByNewSegementLengthOldSegmentLengthBiggerAsNewSegmentLength(void)
If there is a segement bigger than the newSegmentLength, then the new segment should be inserted and ...
Definition: WLine_test.h:390
void testEqualsDeltaOnRealDifferentLines(void)
If both lines are of same size, but there is a point differing on more than the given delta the first...
Definition: WLine_test.h:65
Indicates invalid element access of a container.
Definition: WOutOfBounds.h:36
This only is a 3d double vector.
void testEqualsDeltaDifferentLength(void)
If two lines have different lengths they are considered diffrent regardless on the given delta and th...
Definition: WLine_test.h:50
void testMidPointOnEvenSize(void)
The mid point of a WLine is just the point in the middle of the line.
Definition: WLine_test.h:278
void assert_equals_delta(const WLine &first, const WLine &second, double delta=wlimits::DBL_EPS) const
TS_ASSERT_DELTA needs the operator+, operator- and operator< to be implemented especially for WPositi...
Definition: WLine_test.h:431
void testResamplingByNewSegementLengthWithLineHavingJustOnePoint(void)
Lines with size() == 1, should also remain untouched.
Definition: WLine_test.h:377
void testMidPointOnEmptyLine(void)
When calling midPoint on empty lines => there is no point to return hence an exception is generated...
Definition: WLine_test.h:306
void testResamplingByNewSegmentLengthWithZeroLine(void)
No sample points should remain no sample points.
Definition: WLine_test.h:367
const double DBL_EPS
Smallest double such: 1.0 + DBL_EPS == 1.0 is still true.
Definition: WLimits.cpp:36
void testRemoveAdjacentDuplicates(void)
If there are duplicates next to each other => collapse them.
Definition: WLine_test.h:345
void testEqualityOperator(void)
Two Lines are equal if they have the same points in the same order.
Definition: WLine_test.h:114
void pop_back()
Wrapper around std::vector member function.
Definition: WMixinVector.h:465
void testPathLength(void)
The path length of the line is the accumulated path lengths of all segements (point to point) in that...
Definition: WLine_test.h:165
void testAccessOperatorWithinValidBounds(void)
When accessing an item within 0..length-1 a const reference to the WPosition object should be returne...
Definition: WLine_test.h:133
Unit tests the WLine class.
Definition: WLine_test.h:42
virtual const char * what() const
Returns the message string set on throw.
Definition: WException.cpp:90
void testEmptyLineOnMaxSegementLength(void)
If there no points at all, 0.0 shall be returned.
Definition: WLine_test.h:334
void testManySampelsInBetweenOfTwoOldPoints(void)
If there are many new sample points between two old sample points nothing should fail either...
Definition: WLine_test.h:258
void testResamplingByNewSegementLengthTravelingOutOfTheCircle(void)
Only if a sample point comes out of the circle with radius newSegmentLength then append the point of ...
Definition: WLine_test.h:406
const_reference back() const
Wrapper around std::vector member function.
Definition: WMixinVector.h:537
void reverseOrder()
Reverses the order of the points.
Definition: WLine.cpp:62
size_type size() const
Wrapper around std::vector member function.
Definition: WMixinVector.h:267