1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_basegfx.hxx"
26 #include <basegfx/range/b2dpolyrange.hxx>
27 
28 #include <basegfx/range/b2drange.hxx>
29 #include <basegfx/range/b2drangeclipper.hxx>
30 #include <basegfx/tuple/b2dtuple.hxx>
31 #include <basegfx/polygon/b2dpolypolygon.hxx>
32 
33 #include <boost/bind.hpp>
34 #include <boost/tuple/tuple.hpp>
35 #include <algorithm>
36 #include <vector>
37 
flipOrientation(basegfx::B2VectorOrientation eOrient)38 static basegfx::B2VectorOrientation flipOrientation(
39     basegfx::B2VectorOrientation eOrient)
40 {
41     return eOrient == basegfx::ORIENTATION_POSITIVE ?
42         basegfx::ORIENTATION_NEGATIVE : basegfx::ORIENTATION_POSITIVE;
43 }
44 
45 namespace basegfx
46 {
47     class ImplB2DPolyRange
48     {
updateBounds()49         void updateBounds()
50         {
51             maBounds.reset();
52             std::for_each(maRanges.begin(),
53                           maRanges.end(),
54                           boost::bind(
55                               (void (B2DRange::*)(const B2DRange&))(
56                  &B2DRange::expand),
57                               boost::ref(maBounds),
58                               _1));
59         }
60 
61     public:
ImplB2DPolyRange()62         ImplB2DPolyRange() :
63             maBounds(),
64             maRanges(),
65             maOrient()
66         {}
67 
ImplB2DPolyRange(const B2DPolyRange::ElementType & rElem)68         explicit ImplB2DPolyRange( const B2DPolyRange::ElementType& rElem ) :
69             maBounds( boost::get<0>(rElem) ),
70             maRanges( 1, boost::get<0>(rElem) ),
71             maOrient( 1, boost::get<1>(rElem) )
72         {}
73 
ImplB2DPolyRange(const B2DRange & rRange,B2VectorOrientation eOrient)74         explicit ImplB2DPolyRange( const B2DRange& rRange, B2VectorOrientation eOrient ) :
75             maBounds( rRange ),
76             maRanges( 1, rRange ),
77             maOrient( 1, eOrient )
78         {}
79 
operator ==(const ImplB2DPolyRange & rRHS) const80         bool operator==(const ImplB2DPolyRange& rRHS) const
81         {
82             return maRanges == rRHS.maRanges && maOrient == rRHS.maOrient;
83         }
84 
count() const85         sal_uInt32 count() const
86         {
87             return maRanges.size();
88         }
89 
getElement(sal_uInt32 nIndex) const90         B2DPolyRange::ElementType getElement(sal_uInt32 nIndex) const
91         {
92             return boost::make_tuple(maRanges[nIndex],
93                                      maOrient[nIndex]);
94         }
95 
setElement(sal_uInt32 nIndex,const B2DPolyRange::ElementType & rElement)96         void setElement(sal_uInt32 nIndex, const B2DPolyRange::ElementType& rElement )
97         {
98             maRanges[nIndex] = boost::get<0>(rElement);
99             maOrient[nIndex] = boost::get<1>(rElement);
100             updateBounds();
101         }
102 
setElement(sal_uInt32 nIndex,const B2DRange & rRange,B2VectorOrientation eOrient)103         void setElement(sal_uInt32 nIndex, const B2DRange& rRange, B2VectorOrientation eOrient )
104         {
105             maRanges[nIndex] = rRange;
106             maOrient[nIndex] = eOrient;
107             updateBounds();
108         }
109 
insertElement(sal_uInt32 nIndex,const B2DPolyRange::ElementType & rElement,sal_uInt32 nCount)110         void insertElement(sal_uInt32 nIndex, const B2DPolyRange::ElementType& rElement, sal_uInt32 nCount)
111         {
112             maRanges.insert(maRanges.begin()+nIndex, nCount, boost::get<0>(rElement));
113             maOrient.insert(maOrient.begin()+nIndex, nCount, boost::get<1>(rElement));
114             maBounds.expand(boost::get<0>(rElement));
115         }
116 
insertElement(sal_uInt32 nIndex,const B2DRange & rRange,B2VectorOrientation eOrient,sal_uInt32 nCount)117         void insertElement(sal_uInt32 nIndex, const B2DRange& rRange, B2VectorOrientation eOrient, sal_uInt32 nCount)
118         {
119             maRanges.insert(maRanges.begin()+nIndex, nCount, rRange);
120             maOrient.insert(maOrient.begin()+nIndex, nCount, eOrient);
121             maBounds.expand(rRange);
122         }
123 
appendElement(const B2DPolyRange::ElementType & rElement,sal_uInt32 nCount)124         void appendElement(const B2DPolyRange::ElementType& rElement, sal_uInt32 nCount)
125         {
126             maRanges.insert(maRanges.end(), nCount, boost::get<0>(rElement));
127             maOrient.insert(maOrient.end(), nCount, boost::get<1>(rElement));
128             maBounds.expand(boost::get<0>(rElement));
129         }
130 
appendElement(const B2DRange & rRange,B2VectorOrientation eOrient,sal_uInt32 nCount)131         void appendElement(const B2DRange& rRange, B2VectorOrientation eOrient, sal_uInt32 nCount)
132         {
133             maRanges.insert(maRanges.end(), nCount, rRange);
134             maOrient.insert(maOrient.end(), nCount, eOrient);
135             maBounds.expand(rRange);
136         }
137 
insertPolyRange(sal_uInt32 nIndex,const ImplB2DPolyRange & rPolyRange)138         void insertPolyRange(sal_uInt32 nIndex, const ImplB2DPolyRange& rPolyRange)
139         {
140             maRanges.insert(maRanges.begin()+nIndex, rPolyRange.maRanges.begin(), rPolyRange.maRanges.end());
141             maOrient.insert(maOrient.begin()+nIndex, rPolyRange.maOrient.begin(), rPolyRange.maOrient.end());
142             updateBounds();
143         }
144 
appendPolyRange(const ImplB2DPolyRange & rPolyRange)145         void appendPolyRange(const ImplB2DPolyRange& rPolyRange)
146         {
147             maRanges.insert(maRanges.end(),
148                             rPolyRange.maRanges.begin(),
149                             rPolyRange.maRanges.end());
150             maOrient.insert(maOrient.end(),
151                             rPolyRange.maOrient.begin(),
152                             rPolyRange.maOrient.end());
153             updateBounds();
154         }
155 
remove(sal_uInt32 nIndex,sal_uInt32 nCount)156         void remove(sal_uInt32 nIndex, sal_uInt32 nCount)
157         {
158             maRanges.erase(maRanges.begin()+nIndex,maRanges.begin()+nIndex+nCount);
159             maOrient.erase(maOrient.begin()+nIndex,maOrient.begin()+nIndex+nCount);
160             updateBounds();
161         }
162 
clear()163         void clear()
164         {
165             std::vector<B2DRange> aTmpRanges;
166             std::vector<B2VectorOrientation> aTmpOrient;
167 
168             maRanges.swap(aTmpRanges);
169             maOrient.swap(aTmpOrient);
170 
171             maBounds.reset();
172         }
173 
flip()174         void flip()
175         {
176             std::for_each(maOrient.begin(),
177                           maOrient.end(),
178                           boost::bind(
179                               &flipOrientation,
180                               _1));
181         }
182 
getBounds() const183         B2DRange getBounds() const
184         {
185             return maBounds;
186         }
187 
isInside(const ValueType & rValue) const188 		template< typename ValueType > bool isInside( const ValueType& rValue ) const
189         {
190             if( !maBounds.isInside( rValue ) )
191                 return false;
192 
193             // cannot use boost::bind here, since isInside is overloaded.
194             // It is currently not possible to resolve the overload
195             // by considering one of the other template arguments.
196             std::vector<B2DRange>::const_iterator 		aCurr( maRanges.begin() );
197             const std::vector<B2DRange>::const_iterator aEnd ( maRanges.end() );
198             while( aCurr != aEnd )
199                 if( aCurr->isInside( rValue ) )
200                     return true;
201 
202             return false;
203         }
204 
overlaps(const B2DRange & rRange) const205 		bool overlaps( const B2DRange& rRange ) const
206         {
207             if( !maBounds.overlaps( rRange ) )
208                 return false;
209 
210             const std::vector<B2DRange>::const_iterator aEnd( maRanges.end() );
211             return std::find_if( maRanges.begin(),
212                                  aEnd,
213                                  boost::bind<bool>( boost::mem_fn( &B2DRange::overlaps ),
214                                                     _1,
215                                                     boost::cref(rRange) ) ) != aEnd;
216         }
217 
solveCrossovers() const218         B2DPolyPolygon solveCrossovers() const
219         {
220             return tools::solveCrossovers(maRanges,maOrient);
221         }
222 
begin() const223         const B2DRange* begin() const
224         {
225             if(maRanges.empty())
226                 return 0;
227             else
228                 return &maRanges.front();
229         }
230 
end() const231         const B2DRange* end() const
232         {
233             if(maRanges.empty())
234                 return 0;
235             else
236                 return (&maRanges.back())+1;
237         }
238 
begin()239         B2DRange* begin()
240         {
241             if(maRanges.empty())
242                 return 0;
243             else
244                 return &maRanges.front();
245         }
246 
end()247         B2DRange* end()
248         {
249             if(maRanges.empty())
250                 return 0;
251             else
252                 return (&maRanges.back())+1;
253         }
254 
255     private:
256         B2DRange						 maBounds;
257         std::vector<B2DRange>			 maRanges;
258         std::vector<B2VectorOrientation> maOrient;
259     };
260 
B2DPolyRange()261     B2DPolyRange::B2DPolyRange() :
262         mpImpl()
263     {}
264 
~B2DPolyRange()265     B2DPolyRange::~B2DPolyRange()
266     {}
267 
B2DPolyRange(const ElementType & rElem)268     B2DPolyRange::B2DPolyRange( const ElementType& rElem ) :
269         mpImpl( ImplB2DPolyRange( rElem ) )
270     {}
271 
B2DPolyRange(const B2DRange & rRange,B2VectorOrientation eOrient)272     B2DPolyRange::B2DPolyRange( const B2DRange& rRange, B2VectorOrientation eOrient ) :
273         mpImpl( ImplB2DPolyRange( rRange, eOrient ) )
274     {}
275 
B2DPolyRange(const B2DPolyRange & rRange)276     B2DPolyRange::B2DPolyRange( const B2DPolyRange& rRange ) :
277         mpImpl( rRange.mpImpl )
278     {}
279 
operator =(const B2DPolyRange & rRange)280     B2DPolyRange& B2DPolyRange::operator=( const B2DPolyRange& rRange )
281     {
282         mpImpl = rRange.mpImpl;
283         return *this;
284     }
285 
makeUnique()286     void B2DPolyRange::makeUnique()
287     {
288         mpImpl.make_unique();
289     }
290 
operator ==(const B2DPolyRange & rRange) const291     bool B2DPolyRange::operator==(const B2DPolyRange& rRange) const
292     {
293         if(mpImpl.same_object(rRange.mpImpl))
294             return true;
295 
296         return ((*mpImpl) == (*rRange.mpImpl));
297     }
298 
operator !=(const B2DPolyRange & rRange) const299     bool B2DPolyRange::operator!=(const B2DPolyRange& rRange) const
300     {
301         return !(*this == rRange);
302     }
303 
count() const304     sal_uInt32 B2DPolyRange::count() const
305     {
306         return mpImpl->count();
307     }
308 
getElement(sal_uInt32 nIndex) const309     B2DPolyRange::ElementType B2DPolyRange::getElement(sal_uInt32 nIndex) const
310     {
311         return mpImpl->getElement(nIndex);
312     }
313 
setElement(sal_uInt32 nIndex,const ElementType & rElement)314     void B2DPolyRange::setElement(sal_uInt32 nIndex, const ElementType& rElement )
315     {
316         mpImpl->setElement(nIndex, rElement);
317     }
318 
setElement(sal_uInt32 nIndex,const B2DRange & rRange,B2VectorOrientation eOrient)319     void B2DPolyRange::setElement(sal_uInt32 nIndex, const B2DRange& rRange, B2VectorOrientation eOrient )
320     {
321         mpImpl->setElement(nIndex, rRange, eOrient );
322     }
323 
insertElement(sal_uInt32 nIndex,const ElementType & rElement,sal_uInt32 nCount)324     void B2DPolyRange::insertElement(sal_uInt32 nIndex, const ElementType& rElement, sal_uInt32 nCount)
325     {
326         mpImpl->insertElement(nIndex, rElement, nCount );
327     }
328 
insertElement(sal_uInt32 nIndex,const B2DRange & rRange,B2VectorOrientation eOrient,sal_uInt32 nCount)329     void B2DPolyRange::insertElement(sal_uInt32 nIndex, const B2DRange& rRange, B2VectorOrientation eOrient, sal_uInt32 nCount)
330     {
331         mpImpl->insertElement(nIndex, rRange, eOrient, nCount );
332     }
333 
appendElement(const ElementType & rElement,sal_uInt32 nCount)334     void B2DPolyRange::appendElement(const ElementType& rElement, sal_uInt32 nCount)
335     {
336         mpImpl->appendElement(rElement, nCount);
337     }
338 
appendElement(const B2DRange & rRange,B2VectorOrientation eOrient,sal_uInt32 nCount)339     void B2DPolyRange::appendElement(const B2DRange& rRange, B2VectorOrientation eOrient, sal_uInt32 nCount)
340     {
341         mpImpl->appendElement(rRange, eOrient, nCount );
342     }
343 
insertPolyRange(sal_uInt32 nIndex,const B2DPolyRange & rRange)344     void B2DPolyRange::insertPolyRange(sal_uInt32 nIndex, const B2DPolyRange& rRange)
345     {
346         mpImpl->insertPolyRange(nIndex, *rRange.mpImpl);
347     }
348 
appendPolyRange(const B2DPolyRange & rRange)349     void B2DPolyRange::appendPolyRange(const B2DPolyRange& rRange)
350     {
351         mpImpl->appendPolyRange(*rRange.mpImpl);
352     }
353 
remove(sal_uInt32 nIndex,sal_uInt32 nCount)354     void B2DPolyRange::remove(sal_uInt32 nIndex, sal_uInt32 nCount)
355     {
356         mpImpl->remove(nIndex, nCount);
357     }
358 
clear()359     void B2DPolyRange::clear()
360     {
361         mpImpl->clear();
362     }
363 
flip()364     void B2DPolyRange::flip()
365     {
366         mpImpl->flip();
367     }
368 
getBounds() const369     B2DRange B2DPolyRange::getBounds() const
370     {
371         return mpImpl->getBounds();
372     }
373 
isInside(const B2DTuple & rTuple) const374     bool B2DPolyRange::isInside( const B2DTuple& rTuple ) const
375     {
376         return mpImpl->isInside(rTuple);
377     }
378 
isInside(const B2DRange & rRange) const379     bool B2DPolyRange::isInside( const B2DRange& rRange ) const
380     {
381         return mpImpl->isInside(rRange);
382     }
383 
overlaps(const B2DRange & rRange) const384     bool B2DPolyRange::overlaps( const B2DRange& rRange ) const
385     {
386         return mpImpl->overlaps(rRange);
387     }
388 
solveCrossovers() const389     B2DPolyPolygon B2DPolyRange::solveCrossovers() const
390     {
391         return mpImpl->solveCrossovers();
392     }
393 
begin() const394     const B2DRange* B2DPolyRange::begin() const
395     {
396         return mpImpl->begin();
397     }
398 
end() const399     const B2DRange* B2DPolyRange::end() const
400     {
401         return mpImpl->end();
402     }
403 
begin()404     B2DRange* B2DPolyRange::begin()
405     {
406         return mpImpl->begin();
407     }
408 
end()409     B2DRange* B2DPolyRange::end()
410     {
411         return mpImpl->end();
412     }
413 
414 } // end of namespace basegfx
415 
416 // eof
417