1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2008 by Sun Microsystems, Inc.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * $RCSfile: b2dmultirange.cxx,v $
10  * $Revision: 1.8 $
11  *
12  * This file is part of OpenOffice.org.
13  *
14  * OpenOffice.org is free software: you can redistribute it and/or modify
15  * it under the terms of the GNU Lesser General Public License version 3
16  * only, as published by the Free Software Foundation.
17  *
18  * OpenOffice.org is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU Lesser General Public License version 3 for more details
22  * (a copy is included in the LICENSE file that accompanied this code).
23  *
24  * You should have received a copy of the GNU Lesser General Public License
25  * version 3 along with OpenOffice.org.  If not, see
26  * <http://www.openoffice.org/license.html>
27  * for a copy of the LGPLv3 License.
28  *
29  ************************************************************************/
30 
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_basegfx.hxx"
33 #include <basegfx/range/b2dpolyrange.hxx>
34 
35 #include <basegfx/range/b2drange.hxx>
36 #include <basegfx/range/b2drangeclipper.hxx>
37 #include <basegfx/tuple/b2dtuple.hxx>
38 #include <basegfx/polygon/b2dpolypolygon.hxx>
39 
40 #include <boost/bind.hpp>
41 #include <boost/tuple/tuple.hpp>
42 #include <algorithm>
43 #include <vector>
44 
45 static basegfx::B2VectorOrientation flipOrientation(
46     basegfx::B2VectorOrientation eOrient)
47 {
48     return eOrient == basegfx::ORIENTATION_POSITIVE ?
49         basegfx::ORIENTATION_NEGATIVE : basegfx::ORIENTATION_POSITIVE;
50 }
51 
52 namespace basegfx
53 {
54     class ImplB2DPolyRange
55     {
56         void updateBounds()
57         {
58             maBounds.reset();
59             std::for_each(maRanges.begin(),
60                           maRanges.end(),
61                           boost::bind(
62                               (void (B2DRange::*)(const B2DRange&))(
63                  &B2DRange::expand),
64                               boost::ref(maBounds),
65                               _1));
66         }
67 
68     public:
69         ImplB2DPolyRange() :
70             maBounds(),
71             maRanges(),
72             maOrient()
73         {}
74 
75         explicit ImplB2DPolyRange( const B2DPolyRange::ElementType& rElem ) :
76             maBounds( boost::get<0>(rElem) ),
77             maRanges( 1, boost::get<0>(rElem) ),
78             maOrient( 1, boost::get<1>(rElem) )
79         {}
80 
81         explicit ImplB2DPolyRange( const B2DRange& rRange, B2VectorOrientation eOrient ) :
82             maBounds( rRange ),
83             maRanges( 1, rRange ),
84             maOrient( 1, eOrient )
85         {}
86 
87         bool operator==(const ImplB2DPolyRange& rRHS) const
88         {
89             return maRanges == rRHS.maRanges && maOrient == rRHS.maOrient;
90         }
91 
92         sal_uInt32 count() const
93         {
94             return maRanges.size();
95         }
96 
97         B2DPolyRange::ElementType getElement(sal_uInt32 nIndex) const
98         {
99             return boost::make_tuple(maRanges[nIndex],
100                                      maOrient[nIndex]);
101         }
102 
103         void setElement(sal_uInt32 nIndex, const B2DPolyRange::ElementType& rElement )
104         {
105             maRanges[nIndex] = boost::get<0>(rElement);
106             maOrient[nIndex] = boost::get<1>(rElement);
107             updateBounds();
108         }
109 
110         void setElement(sal_uInt32 nIndex, const B2DRange& rRange, B2VectorOrientation eOrient )
111         {
112             maRanges[nIndex] = rRange;
113             maOrient[nIndex] = eOrient;
114             updateBounds();
115         }
116 
117         void insertElement(sal_uInt32 nIndex, const B2DPolyRange::ElementType& rElement, sal_uInt32 nCount)
118         {
119             maRanges.insert(maRanges.begin()+nIndex, nCount, boost::get<0>(rElement));
120             maOrient.insert(maOrient.begin()+nIndex, nCount, boost::get<1>(rElement));
121             maBounds.expand(boost::get<0>(rElement));
122         }
123 
124         void insertElement(sal_uInt32 nIndex, const B2DRange& rRange, B2VectorOrientation eOrient, sal_uInt32 nCount)
125         {
126             maRanges.insert(maRanges.begin()+nIndex, nCount, rRange);
127             maOrient.insert(maOrient.begin()+nIndex, nCount, eOrient);
128             maBounds.expand(rRange);
129         }
130 
131         void appendElement(const B2DPolyRange::ElementType& rElement, sal_uInt32 nCount)
132         {
133             maRanges.insert(maRanges.end(), nCount, boost::get<0>(rElement));
134             maOrient.insert(maOrient.end(), nCount, boost::get<1>(rElement));
135             maBounds.expand(boost::get<0>(rElement));
136         }
137 
138         void appendElement(const B2DRange& rRange, B2VectorOrientation eOrient, sal_uInt32 nCount)
139         {
140             maRanges.insert(maRanges.end(), nCount, rRange);
141             maOrient.insert(maOrient.end(), nCount, eOrient);
142             maBounds.expand(rRange);
143         }
144 
145         void insertPolyRange(sal_uInt32 nIndex, const ImplB2DPolyRange& rPolyRange)
146         {
147             maRanges.insert(maRanges.begin()+nIndex, rPolyRange.maRanges.begin(), rPolyRange.maRanges.end());
148             maOrient.insert(maOrient.begin()+nIndex, rPolyRange.maOrient.begin(), rPolyRange.maOrient.end());
149             updateBounds();
150         }
151 
152         void appendPolyRange(const ImplB2DPolyRange& rPolyRange)
153         {
154             maRanges.insert(maRanges.end(),
155                             rPolyRange.maRanges.begin(),
156                             rPolyRange.maRanges.end());
157             maOrient.insert(maOrient.end(),
158                             rPolyRange.maOrient.begin(),
159                             rPolyRange.maOrient.end());
160             updateBounds();
161         }
162 
163         void remove(sal_uInt32 nIndex, sal_uInt32 nCount)
164         {
165             maRanges.erase(maRanges.begin()+nIndex,maRanges.begin()+nIndex+nCount);
166             maOrient.erase(maOrient.begin()+nIndex,maOrient.begin()+nIndex+nCount);
167             updateBounds();
168         }
169 
170         void clear()
171         {
172             std::vector<B2DRange> aTmpRanges;
173             std::vector<B2VectorOrientation> aTmpOrient;
174 
175             maRanges.swap(aTmpRanges);
176             maOrient.swap(aTmpOrient);
177 
178             maBounds.reset();
179         }
180 
181         void flip()
182         {
183             std::for_each(maOrient.begin(),
184                           maOrient.end(),
185                           boost::bind(
186                               &flipOrientation,
187                               _1));
188         }
189 
190         B2DRange getBounds() const
191         {
192             return maBounds;
193         }
194 
195 		template< typename ValueType > bool isInside( const ValueType& rValue ) const
196         {
197             if( !maBounds.isInside( rValue ) )
198                 return false;
199 
200             // cannot use boost::bind here, since isInside is overloaded.
201             // It is currently not possible to resolve the overload
202             // by considering one of the other template arguments.
203             std::vector<B2DRange>::const_iterator 		aCurr( maRanges.begin() );
204             const std::vector<B2DRange>::const_iterator aEnd ( maRanges.end() );
205             while( aCurr != aEnd )
206                 if( aCurr->isInside( rValue ) )
207                     return true;
208 
209             return false;
210         }
211 
212 		bool overlaps( const B2DRange& rRange ) const
213         {
214             if( !maBounds.overlaps( rRange ) )
215                 return false;
216 
217             const std::vector<B2DRange>::const_iterator aEnd( maRanges.end() );
218             return std::find_if( maRanges.begin(),
219                                  aEnd,
220                                  boost::bind<bool>( boost::mem_fn( &B2DRange::overlaps ),
221                                                     _1,
222                                                     boost::cref(rRange) ) ) != aEnd;
223         }
224 
225         B2DPolyPolygon solveCrossovers() const
226         {
227             return tools::solveCrossovers(maRanges,maOrient);
228         }
229 
230         const B2DRange* begin() const
231         {
232             if(maRanges.empty())
233                 return 0;
234             else
235                 return &maRanges.front();
236         }
237 
238         const B2DRange* end() const
239         {
240             if(maRanges.empty())
241                 return 0;
242             else
243                 return (&maRanges.back())+1;
244         }
245 
246         B2DRange* begin()
247         {
248             if(maRanges.empty())
249                 return 0;
250             else
251                 return &maRanges.front();
252         }
253 
254         B2DRange* end()
255         {
256             if(maRanges.empty())
257                 return 0;
258             else
259                 return (&maRanges.back())+1;
260         }
261 
262     private:
263         B2DRange						 maBounds;
264         std::vector<B2DRange>			 maRanges;
265         std::vector<B2VectorOrientation> maOrient;
266     };
267 
268     B2DPolyRange::B2DPolyRange() :
269         mpImpl()
270     {}
271 
272     B2DPolyRange::~B2DPolyRange()
273     {}
274 
275     B2DPolyRange::B2DPolyRange( const ElementType& rElem ) :
276         mpImpl( ImplB2DPolyRange( rElem ) )
277     {}
278 
279     B2DPolyRange::B2DPolyRange( const B2DRange& rRange, B2VectorOrientation eOrient ) :
280         mpImpl( ImplB2DPolyRange( rRange, eOrient ) )
281     {}
282 
283     B2DPolyRange::B2DPolyRange( const B2DPolyRange& rRange ) :
284         mpImpl( rRange.mpImpl )
285     {}
286 
287     B2DPolyRange& B2DPolyRange::operator=( const B2DPolyRange& rRange )
288     {
289         mpImpl = rRange.mpImpl;
290         return *this;
291     }
292 
293     void B2DPolyRange::makeUnique()
294     {
295         mpImpl.make_unique();
296     }
297 
298     bool B2DPolyRange::operator==(const B2DPolyRange& rRange) const
299     {
300         if(mpImpl.same_object(rRange.mpImpl))
301             return true;
302 
303         return ((*mpImpl) == (*rRange.mpImpl));
304     }
305 
306     bool B2DPolyRange::operator!=(const B2DPolyRange& rRange) const
307     {
308         return !(*this == rRange);
309     }
310 
311     sal_uInt32 B2DPolyRange::count() const
312     {
313         return mpImpl->count();
314     }
315 
316     B2DPolyRange::ElementType B2DPolyRange::getElement(sal_uInt32 nIndex) const
317     {
318         return mpImpl->getElement(nIndex);
319     }
320 
321     void B2DPolyRange::setElement(sal_uInt32 nIndex, const ElementType& rElement )
322     {
323         mpImpl->setElement(nIndex, rElement);
324     }
325 
326     void B2DPolyRange::setElement(sal_uInt32 nIndex, const B2DRange& rRange, B2VectorOrientation eOrient )
327     {
328         mpImpl->setElement(nIndex, rRange, eOrient );
329     }
330 
331     void B2DPolyRange::insertElement(sal_uInt32 nIndex, const ElementType& rElement, sal_uInt32 nCount)
332     {
333         mpImpl->insertElement(nIndex, rElement, nCount );
334     }
335 
336     void B2DPolyRange::insertElement(sal_uInt32 nIndex, const B2DRange& rRange, B2VectorOrientation eOrient, sal_uInt32 nCount)
337     {
338         mpImpl->insertElement(nIndex, rRange, eOrient, nCount );
339     }
340 
341     void B2DPolyRange::appendElement(const ElementType& rElement, sal_uInt32 nCount)
342     {
343         mpImpl->appendElement(rElement, nCount);
344     }
345 
346     void B2DPolyRange::appendElement(const B2DRange& rRange, B2VectorOrientation eOrient, sal_uInt32 nCount)
347     {
348         mpImpl->appendElement(rRange, eOrient, nCount );
349     }
350 
351     void B2DPolyRange::insertPolyRange(sal_uInt32 nIndex, const B2DPolyRange& rRange)
352     {
353         mpImpl->insertPolyRange(nIndex, *rRange.mpImpl);
354     }
355 
356     void B2DPolyRange::appendPolyRange(const B2DPolyRange& rRange)
357     {
358         mpImpl->appendPolyRange(*rRange.mpImpl);
359     }
360 
361     void B2DPolyRange::remove(sal_uInt32 nIndex, sal_uInt32 nCount)
362     {
363         mpImpl->remove(nIndex, nCount);
364     }
365 
366     void B2DPolyRange::clear()
367     {
368         mpImpl->clear();
369     }
370 
371     void B2DPolyRange::flip()
372     {
373         mpImpl->flip();
374     }
375 
376     B2DRange B2DPolyRange::getBounds() const
377     {
378         return mpImpl->getBounds();
379     }
380 
381     bool B2DPolyRange::isInside( const B2DTuple& rTuple ) const
382     {
383         return mpImpl->isInside(rTuple);
384     }
385 
386     bool B2DPolyRange::isInside( const B2DRange& rRange ) const
387     {
388         return mpImpl->isInside(rRange);
389     }
390 
391     bool B2DPolyRange::overlaps( const B2DRange& rRange ) const
392     {
393         return mpImpl->overlaps(rRange);
394     }
395 
396     B2DPolyPolygon B2DPolyRange::solveCrossovers() const
397     {
398         return mpImpl->solveCrossovers();
399     }
400 
401     const B2DRange* B2DPolyRange::begin() const
402     {
403         return mpImpl->begin();
404     }
405 
406     const B2DRange* B2DPolyRange::end() const
407     {
408         return mpImpl->end();
409     }
410 
411     B2DRange* B2DPolyRange::begin()
412     {
413         return mpImpl->begin();
414     }
415 
416     B2DRange* B2DPolyRange::end()
417     {
418         return mpImpl->end();
419     }
420 
421 } // end of namespace basegfx
422 
423 // eof
424