OpenWalnut  1.5.0dev
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).
315  * BTW: If there are multiple max lengths (equidistant sampled tracts) the first shall be chosen
316  */
318  {
319  WLine line;
320  line.push_back( WPosition( 0, 0, 0 ) );
321  line.push_back( WPosition( 1, 1, 0 ) );
322  line.push_back( WPosition( 2, 0, 0 ) );
323  TS_ASSERT_DELTA( maxSegmentLength( line ), std::sqrt( 2.0 ), wlimits::DBL_EPS );
324  line.push_back( WPosition( 0, 0, 0 ) );
325  TS_ASSERT_DELTA( maxSegmentLength( line ), 2.0, wlimits::DBL_EPS );
326  }
327 
328  /**
329  * If there no points at all, 0.0 shall be returned.
330  */
332  {
333  WLine line;
334  TS_ASSERT_EQUALS( maxSegmentLength( line ), 0.0 );
335  line.push_back( WPosition( 0, 3.1415, 0 ) );
336  TS_ASSERT_EQUALS( maxSegmentLength( line ), 0.0 );
337  }
338 
339  /**
340  * If there are duplicates next to each other => collapse them.
341  */
343  {
344  WLine line;
345  line.push_back( WPosition( 0.1, 3.4, 34254.5 ) );
346  line.push_back( WPosition( 0.1, 3.4, 34254.5 ) );
347  line.push_back( WPosition( 0.1, 3.4, 34254.5 ) );
348  line.push_back( WPosition( 0.1, 3.4, 34254.5 ) );
349  line.push_back( WPosition( 0.0, 0.0, 0.0 ) );
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.1, 3.4, 34254.5 ) );
353  WLine expected;
354  expected.push_back( WPosition( 0.1, 3.4, 34254.5 ) );
355  expected.push_back( WPosition( 0.0, 0.0, 0.0 ) );
356  expected.push_back( WPosition( 0.1, 3.4, 34254.5 ) );
358  assert_equals_delta( line, expected );
359  }
360 
361  /**
362  * No sample points should remain no sample points.
363  */
365  {
366  WLine line;
367  line.resampleBySegmentLength( 3.1415f );
368  assert_equals_delta( line, WLine() );
369  }
370 
371  /**
372  * Lines with size() == 1, should also remain untouched.
373  */
375  {
376  WLine line;
377  line.push_back( WPosition( 0.1, 3.4, 34254.5 ) );
378  WLine expected( line );
379  line.resampleBySegmentLength( 3.1415f );
380  assert_equals_delta( line, expected );
381  }
382 
383  /**
384  * If there is a segement bigger than the newSegmentLength, then the new segment should be
385  * inserted and then with the new point should be proceeded just the same.
386  */
388  {
389  WLine line;
390  line.push_back( WPosition( 0.0, 0.0, 0.0 ) );
391  line.push_back( WPosition( 1.1, 0.0, 0.0 ) );
392  line.resampleBySegmentLength( 1.0 );
393  WLine expected;
394  expected.push_back( WPosition( 0.0, 0.0, 0.0 ) );
395  expected.push_back( WPosition( 1.0, 0.0, 0.0 ) );
396  assert_equals_delta( line, expected );
397  }
398 
399  /**
400  * Only if a sample point comes out of the circle with radius newSegmentLength then append the
401  * point of intersection.
402  */
404  {
405  WLine line;
406  line.push_back( WPosition( 0.0, 0.0, 0.0 ) );
407  line.push_back( WPosition( 1.0, 1.0, 0.0 ) );
408  line.push_back( WPosition( 0.0, 1.0, 0.0 ) );
409  line.push_back( WPosition( 1.0, 2.0, 0.0 ) );
410  line.push_back( WPosition( 0.0, 2.0, 0.0 ) );
411  line.push_back( WPosition( 1.0, 3.0, 0.0 ) );
412  line.resampleBySegmentLength( 3.0 );
413  WLine expected;
414  expected.push_back( WPosition( 0.0, 0.0, 0.0 ) );
415  expected.push_back( WPosition( 0.870829, 2.87083, 0.0 ) );
416  assert_equals_delta( line, expected, 0.00001 );
417  }
418 
419 private:
420  /**
421  * TS_ASSERT_DELTA needs the operator+, operator- and operator< to be implemented especially for WPositions the operator< and operator +
422  * makes not really sense. Hence I implemented an assert by my one, giving reasonable out put.
423  *
424  * \param first First line to compare with
425  * \param second Second line to compare with
426  * \param delta The delta within two points are considered as equally
427  */
428  void assert_equals_delta( const WLine& first, const WLine& second, double delta = wlimits::DBL_EPS ) const
429  {
430  int diffPos = 0;
431  if( ( diffPos = equalsDelta( first, second, delta ) ) != -1 )
432  {
433  using string_utils::operator<<;
434  std::stringstream msg;
435  msg << "Lines are different in at least point: " << diffPos;
436  TS_FAIL( msg.str() );
437  if( static_cast< int >( first.size() ) > diffPos && static_cast< int >( second.size() ) > diffPos )
438  {
439  std::cout << "first line at: " << diffPos << std::endl << first[diffPos] << std::endl;
440  std::cout << "second line at: " << diffPos << std::endl << second[diffPos] << std::endl;
441  }
442  else
443  {
444  std::cout << "lines does not have the same number of points: first=" << first.size() << " second=" << second.size() << std::endl;
445  }
446  std::cout << "first line: " << std::endl << first << std::endl;
447  std::cout << "second line: " << std::endl << second << std::endl;
448  }
449  }
450 };
451 #endif // WLINE_TEST_H
virtual const char * what() const
Returns the message string set on throw.
Definition: WException.cpp:90
Unit tests the WLine class.
Definition: WLine_test.h:43
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
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 testSamplingPointsAreExactlyInTheOldSegmentCenterAndCorners(void)
If the points are exactly in between of a segement nothing should fail.
Definition: WLine_test.h:217
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 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:364
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 testMidPointOnEvenSize(void)
The mid point of a WLine is just the point in the middle of the line.
Definition: WLine_test.h:278
void testResamplingByNewSegementLengthOldSegmentLengthBiggerAsNewSegmentLength(void)
If there is a segement bigger than the newSegmentLength, then the new segment should be inserted and ...
Definition: WLine_test.h:387
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 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 testEmptyLineOnMaxSegementLength(void)
If there no points at all, 0.0 shall be returned.
Definition: WLine_test.h:331
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 testMaxSegementLength(void)
The max segemnent length is the maximum length over all segments (p_i<->p_j).
Definition: WLine_test.h:317
void testEqualityOperator(void)
Two Lines are equal if they have the same points in the same order.
Definition: WLine_test.h:114
void testMidPointOnUnevenSize(void)
When a line has uneven numbered size, the mid point is unique.
Definition: WLine_test.h:292
void testRemoveAdjacentDuplicates(void)
If there are duplicates next to each other => collapse them.
Definition: WLine_test.h:342
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 testOutputOperator(void)
When printing a line to stdout it the output should be as follows: [first_pos, ......
Definition: WLine_test.h:97
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:403
void testResamplingByNewSegementLengthWithLineHavingJustOnePoint(void)
Lines with size() == 1, should also remain untouched.
Definition: WLine_test.h:374
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
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:428
void testNumericalStabilityOfResampling(void)
When resampling with many sample points the numerical errors may sum up.
Definition: WLine_test.h:236
A line is an ordered sequence of WPositions.
Definition: WLine.h:42
void resampleByNumberOfPoints(size_t numPoints)
Resample this line so it has a number of given points afterwards.
Definition: WLine.cpp:78
void reverseOrder()
Reverses the order of the points.
Definition: WLine.cpp:62
void removeAdjacentDuplicates()
Collapse samplepoints which are equal and neighboured.
Definition: WLine.cpp:124
void resampleBySegmentLength(double newSegementLength)
Resample this line so there are only segements of the given length.
Definition: WLine.cpp:147
void pop_back()
Wrapper around std::vector member function.
Definition: WMixinVector.h:465
size_type size() const
Wrapper around std::vector member function.
Definition: WMixinVector.h:267
void push_back(const value_type &value)
Wrapper around std::vector member function.
Definition: WMixinVector.h:457
const_reference back() const
Wrapper around std::vector member function.
Definition: WMixinVector.h:537
Indicates invalid element access of a container.
Definition: WOutOfBounds.h:37
This only is a 3d double vector.
const double DBL_EPS
Smallest double such: 1.0 + DBL_EPS == 1.0 is still true.
Definition: WLimits.cpp:46