summaryrefslogtreecommitdiff
path: root/basegfx/source/range/b2dmultirange.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'basegfx/source/range/b2dmultirange.cxx')
-rw-r--r--basegfx/source/range/b2dmultirange.cxx279
1 files changed, 279 insertions, 0 deletions
diff --git a/basegfx/source/range/b2dmultirange.cxx b/basegfx/source/range/b2dmultirange.cxx
new file mode 100644
index 000000000000..3a47be3b7dc9
--- /dev/null
+++ b/basegfx/source/range/b2dmultirange.cxx
@@ -0,0 +1,279 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_basegfx.hxx"
+#include <basegfx/range/b2drange.hxx>
+#include <basegfx/tuple/b2dtuple.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+#include <basegfx/range/b2dmultirange.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <basegfx/polygon/b2dpolypolygoncutter.hxx>
+#include <boost/bind.hpp>
+#include <boost/mem_fn.hpp>
+#include <algorithm>
+#include <vector>
+
+
+namespace basegfx
+{
+ class ImplB2DMultiRange
+ {
+ public:
+ ImplB2DMultiRange() :
+ maBounds(),
+ maRanges()
+ {
+ }
+
+ explicit ImplB2DMultiRange( const B2DRange& rRange ) :
+ maBounds(),
+ maRanges( 1, rRange )
+ {
+ }
+
+ bool isEmpty() const
+ {
+ // no ranges at all, or all ranges empty
+ return maRanges.empty() ||
+ ::std::count_if( maRanges.begin(),
+ maRanges.end(),
+ ::boost::mem_fn( &B2DRange::isEmpty ) )
+ == static_cast<VectorOfRanges::difference_type>(maRanges.size());
+ }
+
+ void reset()
+ {
+ // swap in empty vector
+ VectorOfRanges aTmp;
+ maRanges.swap( aTmp );
+
+ maBounds.reset();
+ }
+
+ template< typename ValueType > bool isInside( const ValueType& rValue ) const
+ {
+ if( !maBounds.isInside( rValue ) )
+ return false;
+
+ // cannot use ::boost::bind here, since isInside is overloaded.
+ // It is currently not possible to resolve the overload
+ // by considering one of the other template arguments.
+ VectorOfRanges::const_iterator aCurr( maRanges.begin() );
+ const VectorOfRanges::const_iterator aEnd ( maRanges.end() );
+ while( aCurr != aEnd )
+ if( aCurr->isInside( rValue ) )
+ return true;
+
+ return false;
+ }
+
+ bool overlaps( const B2DRange& rRange ) const
+ {
+ if( !maBounds.overlaps( rRange ) )
+ return false;
+
+ const VectorOfRanges::const_iterator aEnd( maRanges.end() );
+ return ::std::find_if( maRanges.begin(),
+ aEnd,
+ ::boost::bind<bool>( ::boost::mem_fn( &B2DRange::overlaps ),
+ _1,
+ rRange ) ) != aEnd;
+ }
+
+ void addRange( const B2DRange& rRange )
+ {
+ maRanges.push_back( rRange );
+ maBounds.expand( rRange );
+ }
+
+ B2DRange getBounds() const
+ {
+ return maBounds;
+ }
+
+ B2DPolyPolygon getPolyPolygon() const
+ {
+ B2DPolyPolygon aRes;
+
+ // Make range vector unique ( have to avoid duplicate
+ // rectangles. The polygon clipper will return an empty
+ // result in this case).
+ VectorOfRanges aUniqueRanges;
+ aUniqueRanges.reserve( maRanges.size() );
+
+ VectorOfRanges::const_iterator aCurr( maRanges.begin() );
+ const VectorOfRanges::const_iterator aEnd ( maRanges.end() );
+ while( aCurr != aEnd )
+ {
+ // TODO(F3): It's plain wasted resources to apply a
+ // general clipping algorithm to the problem at
+ // hand. Go for a dedicated, scan-line-based approach.
+ VectorOfRanges::const_iterator aCurrScan( aCurr+1 );
+ VectorOfRanges::const_iterator aFound( aEnd );
+ while( aCurrScan != aEnd )
+ {
+ if( aCurrScan->equal( *aCurr ) ||
+ aCurrScan->isInside( *aCurr ) )
+ {
+ // current probe is equal to aCurr, or
+ // completely contains aCurr. Thus, stop
+ // searching, because aCurr is definitely not
+ // a member of the unique rect list
+ aFound = aCurrScan;
+ break;
+ }
+
+ ++aCurrScan;
+ }
+
+ if( aFound == aEnd )
+ {
+ // check whether aCurr is fully contained in one
+ // of the already added rects. If yes, we can skip
+ // it.
+ bool bUnique( true );
+ VectorOfRanges::const_iterator aCurrUnique( aUniqueRanges.begin() );
+ VectorOfRanges::const_iterator aEndUnique ( aUniqueRanges.end() );
+ while( aCurrUnique != aEndUnique )
+ {
+ if( aCurrUnique->isInside( *aCurr ) )
+ {
+ // fully contained, no need to add
+ bUnique = false;
+ break;
+ }
+
+ ++aCurrUnique;
+ }
+
+ if( bUnique )
+ aUniqueRanges.push_back( *aCurr );
+ }
+
+ ++aCurr;
+ }
+
+ VectorOfRanges::const_iterator aCurrUnique( aUniqueRanges.begin() );
+ const VectorOfRanges::const_iterator aEndUnique ( aUniqueRanges.end() );
+ while( aCurrUnique != aEndUnique )
+ {
+ // simply merge all unique parts (OR)
+ aRes.append( tools::createPolygonFromRect( *aCurrUnique++ ) );
+ }
+
+ // remove redundant intersections. Note: since all added
+ // rectangles are positively oriented, this method cannot
+ // generate any holes.
+ aRes = basegfx::tools::solveCrossovers(aRes);
+ aRes = basegfx::tools::stripNeutralPolygons(aRes);
+ aRes = basegfx::tools::stripDispensablePolygons(aRes, false);
+
+ return aRes;
+ }
+
+ private:
+ typedef ::std::vector< B2DRange > VectorOfRanges;
+
+ B2DRange maBounds;
+ VectorOfRanges maRanges;
+ };
+
+
+ // ====================================================================
+
+
+ B2DMultiRange::B2DMultiRange() :
+ mpImpl()
+ {
+ }
+
+ B2DMultiRange::B2DMultiRange( const B2DRange& rRange ) :
+ mpImpl( ImplB2DMultiRange( rRange ) )
+ {
+ }
+
+ B2DMultiRange::~B2DMultiRange()
+ {
+ // otherwise, ImplB2DMultiRange would be an incomplete type
+ }
+
+ B2DMultiRange::B2DMultiRange( const B2DMultiRange& rSrc ) :
+ mpImpl( rSrc.mpImpl )
+ {
+ }
+
+ B2DMultiRange& B2DMultiRange::operator=( const B2DMultiRange& rSrc )
+ {
+ mpImpl = rSrc.mpImpl;
+ return *this;
+ }
+
+ bool B2DMultiRange::isEmpty() const
+ {
+ return mpImpl->isEmpty();
+ }
+
+ void B2DMultiRange::reset()
+ {
+ mpImpl->reset();
+ }
+
+ bool B2DMultiRange::isInside( const B2DTuple& rTuple ) const
+ {
+ return mpImpl->isInside( rTuple );
+ }
+
+ bool B2DMultiRange::isInside( const B2DRange& rRange ) const
+ {
+ return mpImpl->isInside( rRange );
+ }
+
+ bool B2DMultiRange::overlaps( const B2DRange& rRange ) const
+ {
+ return mpImpl->overlaps( rRange );
+ }
+
+ void B2DMultiRange::addRange( const B2DRange& rRange )
+ {
+ mpImpl->addRange( rRange );
+ }
+
+ B2DRange B2DMultiRange::getBounds() const
+ {
+ return mpImpl->getBounds();
+ }
+
+ B2DPolyPolygon B2DMultiRange::getPolyPolygon() const
+ {
+ return mpImpl->getPolyPolygon();
+ }
+
+} // end of namespace basegfx
+
+// eof