Medical Imaging Interaction Toolkit  2018.4.99-b585543d
Medical Imaging Interaction Toolkit
mitkContourModel.cpp
Go to the documentation of this file.
1 /*============================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center (DKFZ)
6 All rights reserved.
7 
8 Use of this source code is governed by a 3-clause BSD license that can be
9 found in the LICENSE file.
10 
11 ============================================================================*/
12 #include <mitkContourModel.h>
13 #include <mitkPlaneGeometry.h>
14 
15 mitk::ContourModel::ContourModel() : m_UpdateBoundingBox(true)
16 {
17  // set to initial state
18  this->InitializeEmpty();
19 }
20 
23 {
24  m_SelectedVertex = nullptr;
25 }
26 
28 {
29  m_SelectedVertex = nullptr;
30  this->m_ContourSeries.clear(); // TODO check destruction
31 }
32 
33 void mitk::ContourModel::AddVertex(mitk::Point3D &vertex, int timestep)
34 {
35  if (!this->IsEmptyTimeStep(timestep))
36  {
37  this->AddVertex(vertex, false, timestep);
38  }
39 }
40 
41 void mitk::ContourModel::AddVertex(mitk::Point3D &vertex, bool isControlPoint, int timestep)
42 {
43  if (!this->IsEmptyTimeStep(timestep))
44  {
45  this->m_ContourSeries[timestep]->AddVertex(vertex, isControlPoint);
46  this->InvokeEvent(ContourModelSizeChangeEvent());
47  this->Modified();
48  this->m_UpdateBoundingBox = true;
49  }
50 }
51 
52 void mitk::ContourModel::AddVertex(VertexType &vertex, int timestep)
53 {
54  if (!this->IsEmptyTimeStep(timestep))
55  {
56  this->m_ContourSeries[timestep]->AddVertex(vertex);
57  this->InvokeEvent(ContourModelSizeChangeEvent());
58  this->Modified();
59  this->m_UpdateBoundingBox = true;
60  }
61 }
62 
63 void mitk::ContourModel::AddVertex(const VertexType *vertex, int timestep)
64 {
65  if (vertex != nullptr)
66  {
67  this->m_ContourSeries[timestep]->AddVertex(*const_cast<VertexType *>(vertex));
68  }
69 }
70 
72 {
73  if (!this->IsEmptyTimeStep(timestep))
74  {
75  this->AddVertexAtFront(vertex, false, timestep);
76  }
77 }
78 
79 void mitk::ContourModel::AddVertexAtFront(mitk::Point3D &vertex, bool isControlPoint, int timestep)
80 {
81  if (!this->IsEmptyTimeStep(timestep))
82  {
83  this->m_ContourSeries[timestep]->AddVertexAtFront(vertex, isControlPoint);
84  this->InvokeEvent(ContourModelSizeChangeEvent());
85  this->Modified();
86  this->m_UpdateBoundingBox = true;
87  }
88 }
89 
91 {
92  if (!this->IsEmptyTimeStep(timestep))
93  {
94  this->m_ContourSeries[timestep]->AddVertexAtFront(vertex);
95  this->InvokeEvent(ContourModelSizeChangeEvent());
96  this->Modified();
97  this->m_UpdateBoundingBox = true;
98  }
99 }
100 
101 bool mitk::ContourModel::SetVertexAt(int pointId, const Point3D &point, unsigned int timestep)
102 {
103  if (!this->IsEmptyTimeStep(timestep))
104  {
105  if (pointId >= 0 && this->m_ContourSeries[timestep]->GetSize() > pointId)
106  {
107  this->m_ContourSeries[timestep]->SetVertexAt(pointId, point);
108  this->Modified();
109  this->m_UpdateBoundingBox = true;
110  return true;
111  }
112  return false;
113  }
114  return false;
115 }
116 
117 bool mitk::ContourModel::SetVertexAt(int pointId, const VertexType *vertex, unsigned int timestep)
118 {
119  if (vertex == nullptr)
120  return false;
121 
122  if (!this->IsEmptyTimeStep(timestep))
123  {
124  if (pointId >= 0 && this->m_ContourSeries[timestep]->GetSize() > pointId)
125  {
126  this->m_ContourSeries[timestep]->SetVertexAt(pointId, vertex);
127  this->Modified();
128  this->m_UpdateBoundingBox = true;
129  return true;
130  }
131  return false;
132  }
133  return false;
134 }
135 
136 void mitk::ContourModel::InsertVertexAtIndex(mitk::Point3D &vertex, int index, bool isControlPoint, int timestep)
137 {
138  if (!this->IsEmptyTimeStep(timestep))
139  {
140  if (index >= 0 && this->m_ContourSeries[timestep]->GetSize() > index)
141  {
142  this->m_ContourSeries[timestep]->InsertVertexAtIndex(vertex, isControlPoint, index);
143  this->InvokeEvent(ContourModelSizeChangeEvent());
144  this->Modified();
145  this->m_UpdateBoundingBox = true;
146  }
147  }
148 }
149 
150 bool mitk::ContourModel::IsEmpty(int timestep) const
151 {
152  if (!this->IsEmptyTimeStep(timestep))
153  {
154  return this->m_ContourSeries[timestep]->IsEmpty();
155  }
156  return true;
157 }
158 
160 {
161  return this->IsEmpty(0);
162 }
163 
165 {
166  if (!this->IsEmptyTimeStep(timestep))
167  {
168  return this->m_ContourSeries[timestep]->GetSize();
169  }
170  return -1;
171 }
172 
174 {
175  if (!this->IsEmptyTimeStep(timestep))
176  {
177  return this->m_ContourSeries[timestep]->GetVertexAt(index);
178  }
179  return nullptr;
180 }
181 
182 int mitk::ContourModel::GetIndex(const VertexType *vertex, int timestep)
183 {
184  if (!this->IsEmptyTimeStep(timestep))
185  {
186  return this->m_ContourSeries[timestep]->GetIndex(vertex);
187  }
188  return -1;
189 }
190 
191 void mitk::ContourModel::Close(int timestep)
192 {
193  if (!this->IsEmptyTimeStep(timestep))
194  {
195  this->m_ContourSeries[timestep]->Close();
196  this->InvokeEvent(ContourModelClosedEvent());
197  this->Modified();
198  this->m_UpdateBoundingBox = true;
199  }
200 }
201 
202 void mitk::ContourModel::Open(int timestep)
203 {
204  if (!this->IsEmptyTimeStep(timestep))
205  {
206  this->m_ContourSeries[timestep]->Open();
207  this->InvokeEvent(ContourModelClosedEvent());
208  this->Modified();
209  this->m_UpdateBoundingBox = true;
210  }
211 }
212 
213 void mitk::ContourModel::SetClosed(bool isClosed, int timestep)
214 {
215  if (!this->IsEmptyTimeStep(timestep))
216  {
217  this->m_ContourSeries[timestep]->SetClosed(isClosed);
218  this->InvokeEvent(ContourModelClosedEvent());
219  this->Modified();
220  this->m_UpdateBoundingBox = true;
221  }
222 }
223 
224 bool mitk::ContourModel::IsEmptyTimeStep(unsigned int t) const
225 {
226  return (this->m_ContourSeries.size() <= t);
227 }
228 
229 bool mitk::ContourModel::IsNearContour(mitk::Point3D &point, float eps, int timestep)
230 {
231  if (!this->IsEmptyTimeStep(timestep))
232  {
233  return this->m_ContourSeries[timestep]->IsNearContour(point, eps);
234  }
235  return false;
236 }
237 
238 void mitk::ContourModel::Concatenate(mitk::ContourModel *other, int timestep, bool check)
239 {
240  if (!this->IsEmptyTimeStep(timestep))
241  {
242  if (!this->m_ContourSeries[timestep]->IsClosed())
243  {
244  this->m_ContourSeries[timestep]->Concatenate(other->m_ContourSeries[timestep], check);
245  this->InvokeEvent(ContourModelSizeChangeEvent());
246  this->Modified();
247  this->m_UpdateBoundingBox = true;
248  }
249  }
250 }
251 
253 {
254  return this->IteratorBegin(timestep);
255 }
256 
258 {
259  if (!this->IsEmptyTimeStep(timestep))
260  {
261  return this->m_ContourSeries[timestep]->IteratorBegin();
262  }
263  else
264  {
265  mitkThrow() << "No iterator at invalid timestep " << timestep << ". There are only " << this->GetTimeSteps()
266  << " timesteps available.";
267  }
268 }
269 
271 {
272  return this->IteratorEnd(timestep);
273 }
274 
276 {
277  if (!this->IsEmptyTimeStep(timestep))
278  {
279  return this->m_ContourSeries[timestep]->IteratorEnd();
280  }
281  else
282  {
283  mitkThrow() << "No iterator at invalid timestep " << timestep << ". There are only " << this->GetTimeSteps()
284  << " timesteps available.";
285  }
286 }
287 
288 bool mitk::ContourModel::IsClosed(int timestep) const
289 {
290  if (!this->IsEmptyTimeStep(timestep))
291  {
292  return this->m_ContourSeries[timestep]->IsClosed();
293  }
294  return false;
295 }
296 
297 bool mitk::ContourModel::SelectVertexAt(mitk::Point3D &point, float eps, int timestep)
298 {
299  if (!this->IsEmptyTimeStep(timestep))
300  {
301  this->m_SelectedVertex = this->m_ContourSeries[timestep]->GetVertexAt(point, eps);
302  }
303  return this->m_SelectedVertex != nullptr;
304 }
305 
306 bool mitk::ContourModel::SelectVertexAt(int index, int timestep)
307 {
308  if (!this->IsEmptyTimeStep(timestep) && index >= 0)
309  {
310  return (this->m_SelectedVertex = this->m_ContourSeries[timestep]->GetVertexAt(index));
311  }
312  return false;
313 }
314 
316 {
317  if (!this->IsEmptyTimeStep(timestep))
318  {
319  VertexType *vertex = this->m_ContourSeries[timestep]->GetVertexAt(point, eps);
320  if (vertex != nullptr)
321  {
322  vertex->IsControlPoint = true;
323  return true;
324  }
325  }
326  return false;
327 }
328 
329 bool mitk::ContourModel::SetControlVertexAt(int index, int timestep)
330 {
331  if (!this->IsEmptyTimeStep(timestep) && index >= 0)
332  {
333  VertexType *vertex = this->m_ContourSeries[timestep]->GetVertexAt(index);
334  if (vertex != nullptr)
335  {
336  vertex->IsControlPoint = true;
337  return true;
338  }
339  }
340  return false;
341 }
342 
343 bool mitk::ContourModel::RemoveVertex(const VertexType *vertex, int timestep)
344 {
345  if (!this->IsEmptyTimeStep(timestep))
346  {
347  if (this->m_ContourSeries[timestep]->RemoveVertex(vertex))
348  {
349  this->Modified();
350  this->m_UpdateBoundingBox = true;
351  this->InvokeEvent(ContourModelSizeChangeEvent());
352  return true;
353  }
354  }
355  return false;
356 }
357 
358 bool mitk::ContourModel::RemoveVertexAt(int index, int timestep)
359 {
360  if (!this->IsEmptyTimeStep(timestep))
361  {
362  if (this->m_ContourSeries[timestep]->RemoveVertexAt(index))
363  {
364  this->Modified();
365  this->m_UpdateBoundingBox = true;
366  this->InvokeEvent(ContourModelSizeChangeEvent());
367  return true;
368  }
369  }
370  return false;
371 }
372 
373 bool mitk::ContourModel::RemoveVertexAt(mitk::Point3D &point, float eps, int timestep)
374 {
375  if (!this->IsEmptyTimeStep(timestep))
376  {
377  if (this->m_ContourSeries[timestep]->RemoveVertexAt(point, eps))
378  {
379  this->Modified();
380  this->m_UpdateBoundingBox = true;
381  this->InvokeEvent(ContourModelSizeChangeEvent());
382  return true;
383  }
384  }
385  return false;
386 }
387 
389 {
390  if (this->m_SelectedVertex)
391  {
392  this->ShiftVertex(this->m_SelectedVertex, translate);
393  this->Modified();
394  this->m_UpdateBoundingBox = true;
395  }
396 }
397 
398 void mitk::ContourModel::ShiftContour(mitk::Vector3D &translate, int timestep)
399 {
400  if (!this->IsEmptyTimeStep(timestep))
401  {
402  VertexListType *vList = this->m_ContourSeries[timestep]->GetVertexList();
403  auto it = vList->begin();
404  auto end = vList->end();
405 
406  // shift all vertices
407  while (it != end)
408  {
409  this->ShiftVertex((*it), translate);
410  it++;
411  }
412 
413  this->Modified();
414  this->m_UpdateBoundingBox = true;
415  this->InvokeEvent(ContourModelShiftEvent());
416  }
417 }
418 
420 {
421  vertex->Coordinates[0] += vector[0];
422  vertex->Coordinates[1] += vector[1];
423  vertex->Coordinates[2] += vector[2];
424 }
425 
426 void mitk::ContourModel::Clear(int timestep)
427 {
428  if (!this->IsEmptyTimeStep(timestep))
429  {
430  // clear data at timestep
431  this->m_ContourSeries[timestep]->Clear();
432  this->InitializeEmpty();
433  this->Modified();
434  this->m_UpdateBoundingBox = true;
435  }
436 }
437 
438 void mitk::ContourModel::Expand(unsigned int timeSteps)
439 {
440  std::size_t oldSize = this->m_ContourSeries.size();
441 
442  if (static_cast<std::size_t>(timeSteps) > oldSize)
443  {
444  Superclass::Expand(timeSteps);
445 
446  // insert contours for each new timestep
447  for (std::size_t i = oldSize; i < static_cast<std::size_t>(timeSteps); i++)
448  {
450  }
451 
452  this->InvokeEvent(ContourModelExpandTimeBoundsEvent());
453  }
454 }
455 
457 {
458  // no support for regions
459 }
460 
462 {
463  // no support for regions
464  return false;
465 }
466 
468 {
469  // no support for regions
470  return true;
471 }
472 
474 {
475  return Superclass::GetUpdatedGeometry(t);
476 }
477 
479 {
480  return Superclass::GetGeometry(t);
481 }
482 
483 void mitk::ContourModel::SetRequestedRegion(const itk::DataObject * /*data*/)
484 {
485  // no support for regions
486 }
487 
489 {
490  // clear data and set to initial state again
491  this->ClearData();
492  this->InitializeEmpty();
493  this->Modified();
494  this->m_UpdateBoundingBox = true;
495 }
496 
498 {
499  if (!this->IsEmptyTimeStep(timestep))
500  {
501  this->m_ContourSeries[timestep]->RedistributeControlVertices(this->GetSelectedVertex(), period);
502  this->InvokeEvent(ContourModelClosedEvent());
503  this->Modified();
504  this->m_UpdateBoundingBox = true;
505  }
506 }
507 
509 {
510  // call the superclass, this releases the data of BaseData
511  Superclass::ClearData();
512 
513  // clear out the time resolved contours
514  this->m_ContourSeries.clear();
515 }
516 
518 {
519  this->InitializeEmpty();
520  this->Modified();
521  this->m_UpdateBoundingBox = true;
522 }
523 
525 {
526  mitk::TimeStepType numberOfTimesteps = other.GetTimeGeometry()->CountTimeSteps();
527  this->InitializeTimeGeometry(numberOfTimesteps);
528 
529  for (mitk::TimeStepType currentTimestep = 0; currentTimestep < numberOfTimesteps; currentTimestep++)
530  {
531  this->m_ContourSeries.push_back(mitk::ContourElement::New());
532  this->SetClosed(other.IsClosed(currentTimestep), currentTimestep);
533  }
534 
535  m_SelectedVertex = nullptr;
537  this->Modified();
538  this->m_UpdateBoundingBox = true;
539 }
540 
542 {
543  // clear data at timesteps
544  this->m_ContourSeries.resize(0);
545  this->m_ContourSeries.push_back(mitk::ContourElement::New());
546 
547  // set number of timesteps to one
548  this->InitializeTimeGeometry(1);
549 
550  m_SelectedVertex = nullptr;
552 }
553 
555 {
556  if (this->GetSource())
557  {
558  this->GetSource()->UpdateOutputInformation();
559  }
560 
561  if (this->m_UpdateBoundingBox)
562  {
563  // update the bounds of the geometry according to the stored vertices
564  ScalarType mitkBounds[6];
565 
566  // calculate the boundingbox at each timestep
567  typedef itk::BoundingBox<unsigned long, 3, ScalarType> BoundingBoxType;
568  typedef BoundingBoxType::PointsContainer PointsContainer;
569 
570  int timesteps = this->GetTimeSteps();
571 
572  // iterate over the timesteps
573  for (int currenTimeStep = 0; currenTimeStep < timesteps; currenTimeStep++)
574  {
575  if (dynamic_cast<mitk::PlaneGeometry *>(this->GetGeometry(currenTimeStep)))
576  {
577  // do not update bounds for 2D geometries, as they are unfortunately defined with min bounds 0!
578  return;
579  }
580  else
581  { // we have a 3D geometry -> let's update bounds
582  // only update bounds if the contour was modified
583  if (this->GetMTime() > this->GetGeometry(currenTimeStep)->GetBoundingBox()->GetMTime())
584  {
585  mitkBounds[0] = 0.0;
586  mitkBounds[1] = 0.0;
587  mitkBounds[2] = 0.0;
588  mitkBounds[3] = 0.0;
589  mitkBounds[4] = 0.0;
590  mitkBounds[5] = 0.0;
591 
592  BoundingBoxType::Pointer boundingBox = BoundingBoxType::New();
593 
594  PointsContainer::Pointer points = PointsContainer::New();
595 
596  auto it = this->IteratorBegin(currenTimeStep);
597  auto end = this->IteratorEnd(currenTimeStep);
598 
599  // fill the boundingbox with the points
600  while (it != end)
601  {
602  Point3D currentP = (*it)->Coordinates;
603  BoundingBoxType::PointType p;
604  p.CastFrom(currentP);
605  points->InsertElement(points->Size(), p);
606 
607  it++;
608  }
609 
610  // construct the new boundingBox
611  boundingBox->SetPoints(points);
612  boundingBox->ComputeBoundingBox();
613  BoundingBoxType::BoundsArrayType tmp = boundingBox->GetBounds();
614  mitkBounds[0] = tmp[0];
615  mitkBounds[1] = tmp[1];
616  mitkBounds[2] = tmp[2];
617  mitkBounds[3] = tmp[3];
618  mitkBounds[4] = tmp[4];
619  mitkBounds[5] = tmp[5];
620 
621  // set boundingBox at current timestep
622  BaseGeometry *geometry3d = this->GetGeometry(currenTimeStep);
623  geometry3d->SetBounds(mitkBounds);
624  }
625  }
626  }
627  this->m_UpdateBoundingBox = false;
628  }
629  GetTimeGeometry()->Update();
630 }
631 
633 {
634  // not supported yet
635 }
int GetNumberOfVertices(int timestep=0) const
Returns the number of vertices at a given timestep.
bool RemoveVertexAt(int index, int timestep=0)
Remove a vertex at given index within the container.
itk::SmartPointer< mitk::BaseDataSource > GetSource() const
Get the process object that generated this data object.
ContourModel is a structure of linked vertices defining a contour in 3D space. The vertices are store...
virtual TimeStepType CountTimeSteps() const =0
Returns the number of time steps.
void UpdateOutputInformation() override
Update the OutputInformation of a ContourModel object.
virtual const VertexType * GetVertexAt(int index, int timestep=0) const
Returns the vertex at the index position within the container.
void Concatenate(mitk::ContourModel *other, int timestep=0, bool check=false)
Concatenate two contours. The starting control point of the other will be added at the end of the con...
virtual void SetClosed(bool isClosed, int timestep=0)
Set closed property to given boolean.
mitk::Point3D Coordinates
Coordinates in 3D space.
void ShiftVertex(VertexType *vertex, mitk::Vector3D &vector)
void Initialize() override
Initialize all data objects.
Base of all data objects.
Definition: mitkBaseData.h:37
bool VerifyRequestedRegion() override
Inherit from base data - no region support available for contourModel objects.
Base class of all Operation-classes.
Definition: mitkOperation.h:29
double ScalarType
mitk::ContourElement::VertexIterator VertexIterator
DataCollection - Class to facilitate loading/accessing structured data.
bool SelectVertexAt(int index, int timestep=0)
Mark a vertex at an index in the container as selected.
VertexIterator Begin(int timestep=0) const
Returns a const VertexIterator at the start element of the contour.
void SetRequestedRegionToLargestPossibleRegion() override
Inherit from base data - no region support available for contourModel objects.
void AddVertex(mitk::Point3D &vertex, int timestep=0)
Add a vertex to the contour at given timestep. The vertex is added at the end of contour.
static Pointer New()
virtual bool IsNearContour(mitk::Point3D &point, float eps, int timestep)
Check if mouse cursor is near the contour.
const mitk::TimeGeometry * GetTimeGeometry() const
Return the TimeGeometry of the data as const pointer.
Definition: mitkBaseData.h:61
VertexType * GetSelectedVertex()
Get the current selected vertex.
virtual void Close(int timestep=0)
Close the contour. The last control point will be linked with the first point.
virtual const mitk::BaseGeometry * GetUpdatedGeometry(int t=0)
Get the updated geometry with recomputed bounds.
virtual mitk::BaseGeometry * GetGeometry(int t=0) const
Get the BaseGeometry for timestep t.
int GetIndex(const VertexType *vertex, int timestep=0)
Remove a vertex at given timestep within the container.
ContourModelSeries m_ContourSeries
bool IsEmptyTimeStep(unsigned int t) const override
Check if there isn&#39;t something at this timestep.
void Expand(unsigned int timeSteps) override
Expand the timebounds of the TimeGeometry to given number of timesteps.
#define mitkThrow()
bool IsEmpty() const override
Returns whether the contour model is empty.
void ClearData() override
reset to non-initialized state, release memory
itk::BoundingBox< unsigned long, 3, mitk::ScalarType > BoundingBoxType
void SetRequestedRegion(const itk::DataObject *data) override
Inherit from base data - no region support available for contourModel objects.
void ShiftSelectedVertex(mitk::Vector3D &translate)
Shift the currently selected vertex by a translation vector.
VertexIterator IteratorEnd(int timestep=0) const
Returns a const VertexIterator at the end element of the contour.
std::vcl_size_t TimeStepType
bool IsClosed(int timestep=0) const
Return if the contour is closed or not.
unsigned long GetMTime() const override
Get the modified time of the last change of the contents this data object or its geometry.
void ShiftContour(mitk::Vector3D &translate, int timestep=0)
Shift the whole contour by a translation vector at given timestep.
void Clear() override
Clear the storage container.
VertexIterator End(int timestep=0) const
Returns a const VertexIterator at the end element of the contour.
virtual void RedistributeControlVertices(int period, int timestep)
Redistributes ontrol vertices with a given period (as number of vertices)
void ExecuteOperation(Operation *operation) override
overwrite if the Data can be called by an Interactor (StateMachine).
void SetBounds(const BoundsArrayType &bounds)
Set the bounding box (in index/unit coordinates)
VertexType * m_SelectedVertex
LineSegmentInterpolation m_lineInterpolation
void InitializeEmpty() override
Pure virtual; Must be used in subclasses to get a data object to a valid state. Should at least creat...
bool RequestedRegionIsOutsideOfTheBufferedRegion() override
Inherit from base data - no region support available for contourModel objects.
MITKCORE_EXPORT const ScalarType eps
unsigned int GetTimeSteps() const
Get the number of time steps from the TimeGeometry As the base data has not a data vector given by it...
Definition: mitkBaseData.h:355
mitk::ContourElement::VertexListType VertexListType
void AddVertexAtFront(mitk::Point3D &vertex, int timestep=0)
Add a vertex to the contour at given timestep AT THE FRONT of the contour. The vertex is added at the...
VertexIterator IteratorBegin(int timestep=0) const
Returns a const VertexIterator at the start element of the contour.
void InsertVertexAtIndex(mitk::Point3D &vertex, int index, bool isControlPoint=false, int timestep=0)
Insert a vertex at given index.
bool RemoveVertex(const VertexType *vertex, int timestep=0)
Remove a vertex at given timestep within the container.
void Update()
Updates the geometry.
bool SetControlVertexAt(int index, int timestep=0)
Mark a vertex at an index in the container as control point.
Represents a single vertex of contour.
virtual void InitializeTimeGeometry(unsigned int timeSteps=1)
Initialize the TimeGeometry for a number of time steps. The TimeGeometry is initialized empty and eve...
bool SetVertexAt(int pointId, const mitk::Point3D &point, unsigned int timestep=0)
Set a coordinates for point at given index.
BaseGeometry Describes the geometry of a data object.
virtual void Open(int timestep=0)
Set isClosed to false contour. The link between the last control point the first point will be remove...
BoundingBoxType::BoundsArrayType BoundsArrayType