#i105939# Adds special box clipping support to basegfx
This commit is contained in:
@@ -83,7 +83,7 @@ namespace basegfx
|
|||||||
sal_uInt32 count() const;
|
sal_uInt32 count() const;
|
||||||
|
|
||||||
/// Coordinate interface
|
/// Coordinate interface
|
||||||
basegfx::B2DPoint getB2DPoint(sal_uInt32 nIndex) const;
|
const basegfx::B2DPoint& getB2DPoint(sal_uInt32 nIndex) const;
|
||||||
void setB2DPoint(sal_uInt32 nIndex, const basegfx::B2DPoint& rValue);
|
void setB2DPoint(sal_uInt32 nIndex, const basegfx::B2DPoint& rValue);
|
||||||
|
|
||||||
/// Coordinate insert/append
|
/// Coordinate insert/append
|
||||||
@@ -201,7 +201,7 @@ namespace basegfx
|
|||||||
@return
|
@return
|
||||||
The outer range of the bezier curve/polygon
|
The outer range of the bezier curve/polygon
|
||||||
*/
|
*/
|
||||||
B2DRange getB2DRange() const;
|
const B2DRange& getB2DRange() const;
|
||||||
|
|
||||||
/** insert other 2D polygons
|
/** insert other 2D polygons
|
||||||
|
|
||||||
@@ -261,6 +261,12 @@ namespace basegfx
|
|||||||
|
|
||||||
/// apply transformation given in matrix form
|
/// apply transformation given in matrix form
|
||||||
void transform(const basegfx::B2DHomMatrix& rMatrix);
|
void transform(const basegfx::B2DHomMatrix& rMatrix);
|
||||||
|
|
||||||
|
// point iterators
|
||||||
|
const B2DPoint* begin() const;
|
||||||
|
const B2DPoint* end() const;
|
||||||
|
B2DPoint* begin();
|
||||||
|
B2DPoint* end();
|
||||||
};
|
};
|
||||||
} // end of namespace basegfx
|
} // end of namespace basegfx
|
||||||
|
|
||||||
|
@@ -128,6 +128,12 @@ namespace basegfx
|
|||||||
|
|
||||||
// apply transformation given in matrix form to the polygon
|
// apply transformation given in matrix form to the polygon
|
||||||
void transform(const basegfx::B2DHomMatrix& rMatrix);
|
void transform(const basegfx::B2DHomMatrix& rMatrix);
|
||||||
|
|
||||||
|
// polygon iterators
|
||||||
|
const B2DPolygon* begin() const;
|
||||||
|
const B2DPolygon* end() const;
|
||||||
|
B2DPolygon* begin();
|
||||||
|
B2DPolygon* end();
|
||||||
};
|
};
|
||||||
} // end of namespace basegfx
|
} // end of namespace basegfx
|
||||||
|
|
||||||
|
@@ -1,117 +0,0 @@
|
|||||||
/*************************************************************************
|
|
||||||
*
|
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
||||||
*
|
|
||||||
* Copyright 2008 by Sun Microsystems, Inc.
|
|
||||||
*
|
|
||||||
* OpenOffice.org - a multi-platform office productivity suite
|
|
||||||
*
|
|
||||||
* $RCSfile: b2dmultirange.hxx,v $
|
|
||||||
* $Revision: 1.6 $
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
************************************************************************/
|
|
||||||
|
|
||||||
#ifndef _BGFX_RANGE_B2DMULTIRANGE_HXX
|
|
||||||
#define _BGFX_RANGE_B2DMULTIRANGE_HXX
|
|
||||||
|
|
||||||
#include <o3tl/cow_wrapper.hxx>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
|
|
||||||
namespace basegfx
|
|
||||||
{
|
|
||||||
class B2DTuple;
|
|
||||||
class B2DRange;
|
|
||||||
class B2DPolyPolygon;
|
|
||||||
class ImplB2DMultiRange;
|
|
||||||
|
|
||||||
/** Multiple ranges in one object.
|
|
||||||
|
|
||||||
This class combines multiple ranges in one object, providing a
|
|
||||||
total, enclosing range for it.
|
|
||||||
|
|
||||||
You can use this class e.g. when updating views containing
|
|
||||||
rectangular objects. Add each modified object to a
|
|
||||||
B2DMultiRange, then test each viewable object against
|
|
||||||
intersection with the multi range.
|
|
||||||
*/
|
|
||||||
class B2DMultiRange
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
B2DMultiRange();
|
|
||||||
~B2DMultiRange();
|
|
||||||
|
|
||||||
/** Create a multi range with exactly one containing range
|
|
||||||
*/
|
|
||||||
explicit B2DMultiRange( const B2DRange& rRange );
|
|
||||||
|
|
||||||
B2DMultiRange( const B2DMultiRange& );
|
|
||||||
B2DMultiRange& operator=( const B2DMultiRange& );
|
|
||||||
|
|
||||||
/** Check whether range is empty.
|
|
||||||
|
|
||||||
@return true, if this object either contains no ranges at
|
|
||||||
all, or all contained ranges are empty.
|
|
||||||
*/
|
|
||||||
bool isEmpty() const;
|
|
||||||
|
|
||||||
/** Reset to empty.
|
|
||||||
|
|
||||||
After this call, the object will not contain any ranges,
|
|
||||||
and isEmpty() will return true.
|
|
||||||
*/
|
|
||||||
void reset();
|
|
||||||
|
|
||||||
/** Test whether given tuple is inside one or more of the
|
|
||||||
included ranges.
|
|
||||||
*/
|
|
||||||
bool isInside( const B2DTuple& rTuple ) const;
|
|
||||||
|
|
||||||
/** Test whether given range is inside one or more of the
|
|
||||||
included ranges.
|
|
||||||
*/
|
|
||||||
bool isInside( const B2DRange& rRange ) const;
|
|
||||||
|
|
||||||
/** Test whether given range overlaps one or more of the
|
|
||||||
included ranges.
|
|
||||||
*/
|
|
||||||
bool overlaps( const B2DRange& rRange ) const;
|
|
||||||
|
|
||||||
/** Add given range to the number of contained ranges.
|
|
||||||
*/
|
|
||||||
void addRange( const B2DRange& rRange );
|
|
||||||
|
|
||||||
/** Get overall bound rect for all included ranges.
|
|
||||||
*/
|
|
||||||
B2DRange getBounds() const;
|
|
||||||
|
|
||||||
/** Request poly-polygon representing the added ranges.
|
|
||||||
|
|
||||||
This method creates a poly-polygon, consisting exactly out
|
|
||||||
of the contained ranges.
|
|
||||||
*/
|
|
||||||
B2DPolyPolygon getPolyPolygon() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
o3tl::cow_wrapper< ImplB2DMultiRange > mpImpl;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* _BGFX_RANGE_B2DMULTIRANGE_HXX */
|
|
139
basegfx/inc/basegfx/range/b2dpolyrange.hxx
Normal file
139
basegfx/inc/basegfx/range/b2dpolyrange.hxx
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
/*************************************************************************
|
||||||
|
*
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* Copyright 2008 by Sun Microsystems, Inc.
|
||||||
|
*
|
||||||
|
* OpenOffice.org - a multi-platform office productivity suite
|
||||||
|
*
|
||||||
|
* $RCSfile: b2dmultirange.hxx,v $
|
||||||
|
* $Revision: 1.6 $
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _BGFX_RANGE_B2DPOLYRANGE_HXX
|
||||||
|
#define _BGFX_RANGE_B2DPOLYRANGE_HXX
|
||||||
|
|
||||||
|
#include <o3tl/cow_wrapper.hxx>
|
||||||
|
#include <boost/tuple/tuple.hpp>
|
||||||
|
#include <basegfx/vector/b2enums.hxx>
|
||||||
|
|
||||||
|
namespace basegfx
|
||||||
|
{
|
||||||
|
class B2DTuple;
|
||||||
|
class B2DRange;
|
||||||
|
class B2DPolyPolygon;
|
||||||
|
class ImplB2DPolyRange;
|
||||||
|
|
||||||
|
/** Multiple ranges in one object.
|
||||||
|
|
||||||
|
This class combines multiple ranges in one object, providing a
|
||||||
|
total, enclosing range for it.
|
||||||
|
|
||||||
|
You can use this class e.g. when updating views containing
|
||||||
|
rectangular objects. Add each modified object to a
|
||||||
|
B2DMultiRange, then test each viewable object against
|
||||||
|
intersection with the multi range.
|
||||||
|
|
||||||
|
Similar in spirit to the poly-polygon vs. polygon relationship.
|
||||||
|
|
||||||
|
Note that comparable to polygons, a poly-range can also
|
||||||
|
contain 'holes' - this is encoded via polygon orientation at
|
||||||
|
the poly-polygon, and via explicit flags for the poly-range.
|
||||||
|
*/
|
||||||
|
class B2DPolyRange
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef boost::tuple<B2DRange,B2VectorOrientation> ElementType ;
|
||||||
|
|
||||||
|
B2DPolyRange();
|
||||||
|
~B2DPolyRange();
|
||||||
|
|
||||||
|
/** Create a multi range with exactly one containing range
|
||||||
|
*/
|
||||||
|
explicit B2DPolyRange( const ElementType& rElement );
|
||||||
|
B2DPolyRange( const B2DRange& rRange, B2VectorOrientation eOrient );
|
||||||
|
B2DPolyRange( const B2DPolyRange& );
|
||||||
|
B2DPolyRange& operator=( const B2DPolyRange& );
|
||||||
|
|
||||||
|
/// unshare this poly-range with all internally shared instances
|
||||||
|
void makeUnique();
|
||||||
|
|
||||||
|
bool operator==(const B2DPolyRange&) const;
|
||||||
|
bool operator!=(const B2DPolyRange&) const;
|
||||||
|
|
||||||
|
/// Number of included ranges
|
||||||
|
sal_uInt32 count() const;
|
||||||
|
|
||||||
|
ElementType getElement(sal_uInt32 nIndex) const;
|
||||||
|
void setElement(sal_uInt32 nIndex, const ElementType& rElement );
|
||||||
|
void setElement(sal_uInt32 nIndex, const B2DRange& rRange, B2VectorOrientation eOrient );
|
||||||
|
|
||||||
|
// insert/append a single range
|
||||||
|
void insertElement(sal_uInt32 nIndex, const ElementType& rElement, sal_uInt32 nCount = 1);
|
||||||
|
void insertElement(sal_uInt32 nIndex, const B2DRange& rRange, B2VectorOrientation eOrient, sal_uInt32 nCount = 1);
|
||||||
|
void appendElement(const ElementType& rElement, sal_uInt32 nCount = 1);
|
||||||
|
void appendElement(const B2DRange& rRange, B2VectorOrientation eOrient, sal_uInt32 nCount = 1);
|
||||||
|
|
||||||
|
// insert/append multiple ranges
|
||||||
|
void insertPolyRange(sal_uInt32 nIndex, const B2DPolyRange&);
|
||||||
|
void appendPolyRange(const B2DPolyRange&);
|
||||||
|
|
||||||
|
void remove(sal_uInt32 nIndex, sal_uInt32 nCount = 1);
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
// flip range orientations - converts holes to solids, and vice versa
|
||||||
|
void flip();
|
||||||
|
|
||||||
|
/** Get overall range
|
||||||
|
|
||||||
|
@return
|
||||||
|
The union range of all contained ranges
|
||||||
|
*/
|
||||||
|
B2DRange getBounds() const;
|
||||||
|
|
||||||
|
/** Test whether given tuple is inside one or more of the
|
||||||
|
included ranges. Does *not* use overall range, but checks
|
||||||
|
individually.
|
||||||
|
*/
|
||||||
|
bool isInside( const B2DTuple& rTuple ) const;
|
||||||
|
|
||||||
|
/** Test whether given range is inside one or more of the
|
||||||
|
included ranges. Does *not* use overall range, but checks
|
||||||
|
individually.
|
||||||
|
*/
|
||||||
|
bool isInside( const B2DRange& rRange ) const;
|
||||||
|
|
||||||
|
/** Test whether given range overlaps one or more of the
|
||||||
|
included ranges. Does *not* use overall range, but checks
|
||||||
|
individually.
|
||||||
|
*/
|
||||||
|
bool overlaps( const B2DRange& rRange ) const;
|
||||||
|
|
||||||
|
/** Request a poly-polygon with solved cross-overs
|
||||||
|
*/
|
||||||
|
B2DPolyPolygon solveCrossovers() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
o3tl::cow_wrapper< ImplB2DPolyRange > mpImpl;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* _BGFX_RANGE_B2DPOLYRANGE_HXX */
|
53
basegfx/inc/basegfx/range/b2drangeclipper.hxx
Normal file
53
basegfx/inc/basegfx/range/b2drangeclipper.hxx
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
/*************************************************************************
|
||||||
|
*
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* Copyright 2008 by Sun Microsystems, Inc.
|
||||||
|
*
|
||||||
|
* OpenOffice.org - a multi-platform office productivity suite
|
||||||
|
*
|
||||||
|
* $RCSfile: b2dmultirange.hxx,v $
|
||||||
|
* $Revision: 1.6 $
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _BGFX_RANGE_B2DRANGECLIPPER_HXX
|
||||||
|
#define _BGFX_RANGE_B2DRANGECLIPPER_HXX
|
||||||
|
|
||||||
|
#include <basegfx/range/b2dpolyrange.hxx>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace basegfx
|
||||||
|
{
|
||||||
|
namespace tools
|
||||||
|
{
|
||||||
|
/** Extract poly-polygon w/o self-intersections from poly-range
|
||||||
|
|
||||||
|
Similar to the solveCrossovers(const B2DPolyPolygon&)
|
||||||
|
method, this one calculates a self-intersection-free
|
||||||
|
poly-polygon with the same topology, and encoding
|
||||||
|
inside/outsidedness via polygon orientation and layering.
|
||||||
|
*/
|
||||||
|
B2DPolyPolygon solveCrossovers(const std::vector<B2DRange>& rRanges,
|
||||||
|
const std::vector<B2VectorOrientation>& rOrientations);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* _BGFX_RANGE_B2DRANGECLIPPER_HXX */
|
344
basegfx/qa/mkpolygons.pl
Normal file
344
basegfx/qa/mkpolygons.pl
Normal file
@@ -0,0 +1,344 @@
|
|||||||
|
:
|
||||||
|
eval 'exec perl -wS $0 ${1+"$@"}'
|
||||||
|
if 0;
|
||||||
|
|
||||||
|
#
|
||||||
|
# 2009 Copyright Novell, Inc. & Sun Microsystems, Inc.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
|
||||||
|
use IO::File;
|
||||||
|
use Cwd;
|
||||||
|
use File::Spec;
|
||||||
|
use File::Spec::Functions;
|
||||||
|
use File::Temp;
|
||||||
|
use File::Path;
|
||||||
|
|
||||||
|
$TempDir = "";
|
||||||
|
|
||||||
|
|
||||||
|
# all the XML package generation is a blatant rip from AF's
|
||||||
|
# write-calc-doc.pl
|
||||||
|
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Open a file with the given name.
|
||||||
|
# First it is checked if the temporary directory, in which all files for
|
||||||
|
# the document are gathered, is already present and create it if it is not.
|
||||||
|
# Then create the path to the file inside the temporary directory.
|
||||||
|
# Finally open the file and return a file handle to it.
|
||||||
|
#
|
||||||
|
sub open_file
|
||||||
|
{
|
||||||
|
my $filename = pop @_;
|
||||||
|
|
||||||
|
# Create base directory of temporary directory tree if not alreay
|
||||||
|
# present.
|
||||||
|
if ($TempDir eq "")
|
||||||
|
{
|
||||||
|
$TempDir = File::Temp::tempdir (CLEANUP => 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create the path to the file.
|
||||||
|
my $fullname = File::Spec->catfile ($TempDir, $filename);
|
||||||
|
my ($volume,$directories,$file) = File::Spec->splitpath ($fullname);
|
||||||
|
mkpath (File::Spec->catpath ($volume,$directories,""));
|
||||||
|
|
||||||
|
# Open the file and return a file handle to it.
|
||||||
|
return new IO::File ($fullname, "w");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Zip the files in the directory tree into the given file.
|
||||||
|
#
|
||||||
|
sub zip_dirtree
|
||||||
|
{
|
||||||
|
my $filename = pop @_;
|
||||||
|
|
||||||
|
my $cwd = getcwd;
|
||||||
|
my $zip_name = $filename;
|
||||||
|
|
||||||
|
# We are about to change the directory.
|
||||||
|
# Therefore create an absolute pathname for the zip archive.
|
||||||
|
|
||||||
|
# First transfer the drive from $cwd to $zip_name. This is a
|
||||||
|
# workaround for a bug in file_name_is_absolute which thinks
|
||||||
|
# the the path \bla is an absolute path under DOS.
|
||||||
|
my ($volume,$directories,$file) = File::Spec->splitpath ($zip_name);
|
||||||
|
my ($volume_cwd,$directories_cwd,$file_cwd) = File::Spec->splitpath ($cwd);
|
||||||
|
$volume = $volume_cwd if ($volume eq "");
|
||||||
|
$zip_name = File::Spec->catpath ($volume,$directories,$file);
|
||||||
|
|
||||||
|
# Add the current working directory to a relative path.
|
||||||
|
if ( ! file_name_is_absolute ($zip_name))
|
||||||
|
{
|
||||||
|
$zip_name = File::Spec->catfile ($cwd, $zip_name);
|
||||||
|
|
||||||
|
# Try everything to clean up the name.
|
||||||
|
$zip_name = File::Spec->rel2abs ($filename);
|
||||||
|
$zip_name = File::Spec->canonpath ($zip_name);
|
||||||
|
|
||||||
|
# Remove .. directories from the middle of the path.
|
||||||
|
while ($zip_name =~ /\/[^\/][^\.\/][^\/]*\/\.\.\//)
|
||||||
|
{
|
||||||
|
$zip_name = $` . "/" . $';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Just in case the zip program gets confused by an existing file with the
|
||||||
|
# same name as the one to be written that file is removed first.
|
||||||
|
if ( -e $filename)
|
||||||
|
{
|
||||||
|
if (unlink ($filename) == 0)
|
||||||
|
{
|
||||||
|
print "Existing file $filename could not be deleted.\n";
|
||||||
|
print "Please close the application that uses it, then try again.\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Finally create the zip file. First change into the temporary directory
|
||||||
|
# so that the resulting zip file contains only paths relative to it.
|
||||||
|
print "zipping [$ZipCmd $ZipFlags $zip_name *]\n";
|
||||||
|
chdir ($TempDir);
|
||||||
|
system ("$ZipCmd $ZipFlags $zip_name *");
|
||||||
|
chdir ($cwd);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sub writeHeader
|
||||||
|
{
|
||||||
|
print $OUT qq~<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<office:document-content xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:presentation="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:smil="urn:oasis:names:tc:opendocument:xmlns:smil-compatible:1.0" xmlns:anim="urn:oasis:names:tc:opendocument:xmlns:animation:1.0" office:version="1.0">
|
||||||
|
<office:scripts/>
|
||||||
|
<office:automatic-styles>
|
||||||
|
<style:style style:name="dp1" style:family="drawing-page">
|
||||||
|
<style:drawing-page-properties presentation:background-visible="true" presentation:background-objects-visible="true" presentation:display-footer="true" presentation:display-page-number="false" presentation:display-date-time="true"/>
|
||||||
|
</style:style>
|
||||||
|
<style:style style:name="gr1" style:family="graphic" style:parent-style-name="standard">
|
||||||
|
<style:graphic-properties draw:textarea-horizontal-align="center" draw:fill="none" draw:stroke="none" draw:textarea-vertical-align="middle"/>
|
||||||
|
</style:style>
|
||||||
|
<style:style style:name="gr2" style:family="graphic" style:parent-style-name="standard">
|
||||||
|
<style:graphic-properties draw:textarea-horizontal-align="center" draw:textarea-vertical-align="middle"/>
|
||||||
|
</style:style>
|
||||||
|
<style:style style:name="pr1" style:family="presentation" style:parent-style-name="Default-title">
|
||||||
|
<style:graphic-properties draw:fill-color="#ffffff" draw:auto-grow-height="true" fo:min-height="3.508cm"/>
|
||||||
|
</style:style>
|
||||||
|
<style:style style:name="pr2" style:family="presentation" style:parent-style-name="Default-notes">
|
||||||
|
<style:graphic-properties draw:fill-color="#ffffff" draw:auto-grow-height="true" fo:min-height="13.367cm"/>
|
||||||
|
</style:style>
|
||||||
|
<style:style style:name="P1" style:family="paragraph">
|
||||||
|
<style:paragraph-properties fo:margin-left="0cm" fo:margin-right="0cm" fo:text-indent="0cm"/>
|
||||||
|
</style:style>
|
||||||
|
<style:style style:name="P2" style:family="paragraph">
|
||||||
|
<style:paragraph-properties fo:margin-left="0.6cm" fo:margin-right="0cm" fo:text-indent="-0.6cm"/>
|
||||||
|
</style:style>
|
||||||
|
<text:list-style style:name="L1">
|
||||||
|
<text:list-level-style-bullet text:level="1" text:bullet-char="●">
|
||||||
|
<style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/>
|
||||||
|
</text:list-level-style-bullet>
|
||||||
|
<text:list-level-style-bullet text:level="2" text:bullet-char="●">
|
||||||
|
<style:list-level-properties text:space-before="0.6cm" text:min-label-width="0.6cm"/>
|
||||||
|
<style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/>
|
||||||
|
</text:list-level-style-bullet>
|
||||||
|
<text:list-level-style-bullet text:level="3" text:bullet-char="●">
|
||||||
|
<style:list-level-properties text:space-before="1.2cm" text:min-label-width="0.6cm"/>
|
||||||
|
<style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/>
|
||||||
|
</text:list-level-style-bullet>
|
||||||
|
<text:list-level-style-bullet text:level="4" text:bullet-char="●">
|
||||||
|
<style:list-level-properties text:space-before="1.8cm" text:min-label-width="0.6cm"/>
|
||||||
|
<style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/>
|
||||||
|
</text:list-level-style-bullet>
|
||||||
|
<text:list-level-style-bullet text:level="5" text:bullet-char="●">
|
||||||
|
<style:list-level-properties text:space-before="2.4cm" text:min-label-width="0.6cm"/>
|
||||||
|
<style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/>
|
||||||
|
</text:list-level-style-bullet>
|
||||||
|
<text:list-level-style-bullet text:level="6" text:bullet-char="●">
|
||||||
|
<style:list-level-properties text:space-before="3cm" text:min-label-width="0.6cm"/>
|
||||||
|
<style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/>
|
||||||
|
</text:list-level-style-bullet>
|
||||||
|
<text:list-level-style-bullet text:level="7" text:bullet-char="●">
|
||||||
|
<style:list-level-properties text:space-before="3.6cm" text:min-label-width="0.6cm"/>
|
||||||
|
<style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/>
|
||||||
|
</text:list-level-style-bullet>
|
||||||
|
<text:list-level-style-bullet text:level="8" text:bullet-char="●">
|
||||||
|
<style:list-level-properties text:space-before="4.2cm" text:min-label-width="0.6cm"/>
|
||||||
|
<style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/>
|
||||||
|
</text:list-level-style-bullet>
|
||||||
|
<text:list-level-style-bullet text:level="9" text:bullet-char="●">
|
||||||
|
<style:list-level-properties text:space-before="4.8cm" text:min-label-width="0.6cm"/>
|
||||||
|
<style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/>
|
||||||
|
</text:list-level-style-bullet>
|
||||||
|
</text:list-style>
|
||||||
|
</office:automatic-styles>
|
||||||
|
<office:body>
|
||||||
|
<office:presentation>
|
||||||
|
~;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sub writeSlideHeader
|
||||||
|
{
|
||||||
|
my $titleText = pop @_;
|
||||||
|
my $slideNum = pop @_;
|
||||||
|
|
||||||
|
print $OUT " <draw:page draw:name=\"page1\" draw:style-name=\"dp1\" draw:master-page-name=\"Default\">\n";
|
||||||
|
print $OUT " <office:forms form:automatic-focus=\"false\" form:apply-design-mode=\"false\"/>\n";
|
||||||
|
print $OUT " <draw:rect draw:style-name=\"gr1\" draw:text-style-name=\"P1\" draw:id=\"id$slideNum\" draw:layer=\"layout\" svg:width=\"17.5cm\" svg:height=\"6cm\" svg:x=\"5cm\" svg:y=\"4cm\">\n";
|
||||||
|
print $OUT " <text:p text:style-name=\"P2\">Slide: $slideNum</text:p>\n";
|
||||||
|
print $OUT " <text:p text:style-name=\"P2\">Path: $titleText</text:p>\n";
|
||||||
|
print $OUT " </draw:rect>\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sub writeSlideFooter
|
||||||
|
{
|
||||||
|
print $OUT " <presentation:notes draw:style-name=\"dp1\">\n";
|
||||||
|
print $OUT " <draw:page-thumbnail draw:style-name=\"gr1\" draw:layer=\"layout\" svg:width=\"14.851cm\" svg:height=\"11.138cm\" svg:x=\"3.068cm\" svg:y=\"2.257cm\" draw:page-number=\"1\" presentation:class=\"page\"/>\n";
|
||||||
|
print $OUT " <draw:frame presentation:style-name=\"pr3\" draw:layer=\"layout\" svg:width=\"16.79cm\" svg:height=\"13.116cm\" svg:x=\"2.098cm\" svg:y=\"14.109cm\" presentation:class=\"notes\" presentation:placeholder=\"true\">\n";
|
||||||
|
print $OUT " <draw:text-box/>\n";
|
||||||
|
print $OUT " </draw:frame>\n";
|
||||||
|
print $OUT " </presentation:notes>\n";
|
||||||
|
print $OUT " </draw:page>\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
sub writeFooter
|
||||||
|
{
|
||||||
|
print $OUT qq~ <presentation:settings presentation:full-screen="false"/>
|
||||||
|
</office:presentation>
|
||||||
|
</office:body>
|
||||||
|
</office:document-content>
|
||||||
|
~;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sub writePath
|
||||||
|
{
|
||||||
|
my $pathAry = pop @_;
|
||||||
|
my $path = $pathAry->[1];
|
||||||
|
my $viewBox = $pathAry->[0];
|
||||||
|
|
||||||
|
print $OUT " <draw:path draw:style-name=\"gr2\" draw:text-style-name=\"P1\" draw:layer=\"layout\" svg:width=\"10cm\" svg:height=\"10cm\" svg:x=\"5cm\" svg:y=\"5cm\" svg:viewBox=\"";
|
||||||
|
print $OUT $viewBox;
|
||||||
|
print $OUT "\" svg:d=\"";
|
||||||
|
print $OUT $path;
|
||||||
|
print $OUT "\">\n";
|
||||||
|
print $OUT " <text:p/>\n";
|
||||||
|
print $OUT " </draw:path>\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
sub writeManifest
|
||||||
|
{
|
||||||
|
my $outFile = open_file("META-INF/manifest.xml");
|
||||||
|
|
||||||
|
print $outFile qq~<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE manifest:manifest PUBLIC "-//OpenOffice.org//DTD Manifest 1.0//EN" "Manifest.dtd">
|
||||||
|
<manifest:manifest xmlns:manifest="urn:oasis:names:tc:opendocument:xmlns:manifest:1.0">
|
||||||
|
<manifest:file-entry manifest:media-type="application/vnd.oasis.opendocument.presentation" manifest:full-path="/"/>
|
||||||
|
<manifest:file-entry manifest:media-type="text/xml" manifest:full-path="content.xml"/>
|
||||||
|
</manifest:manifest>
|
||||||
|
~;
|
||||||
|
|
||||||
|
$outFile->close;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Print usage information.
|
||||||
|
#
|
||||||
|
sub usage ()
|
||||||
|
{
|
||||||
|
print <<END_OF_USAGE;
|
||||||
|
usage: $0 <option>* [<SvgD-values>]
|
||||||
|
|
||||||
|
output-file-name defaults to polygons.odp.
|
||||||
|
|
||||||
|
-h Print this usage information.
|
||||||
|
-o output-file-name
|
||||||
|
END_OF_USAGE
|
||||||
|
}
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Process the command line.
|
||||||
|
#
|
||||||
|
sub process_command_line
|
||||||
|
{
|
||||||
|
foreach (@ARGV)
|
||||||
|
{
|
||||||
|
if (/^-h/)
|
||||||
|
{
|
||||||
|
usage;
|
||||||
|
exit 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$global_output_name = "polygons.odp";
|
||||||
|
my $j = 0, $noMoreOptions = 0;
|
||||||
|
for (my $i=0; $i<$#ARGV; $i++)
|
||||||
|
{
|
||||||
|
if ( !$noMoreOptions and $ARGV[$i] eq "-o")
|
||||||
|
{
|
||||||
|
$i++;
|
||||||
|
$global_output_name = $ARGV[$i];
|
||||||
|
}
|
||||||
|
elsif ( !$noMoreOptions and $ARGV[$i] eq "--")
|
||||||
|
{
|
||||||
|
$noMoreOptions = 1;
|
||||||
|
}
|
||||||
|
elsif ( !$noMoreOptions and $ARGV[$i] =~ /^-/)
|
||||||
|
{
|
||||||
|
print "Unknown option $ARGV[$i]\n";
|
||||||
|
usage;
|
||||||
|
exit 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
push(@paths, [$ARGV[$i],$ARGV[$i+1]]);
|
||||||
|
$i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
print "output to $global_output_name\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Main
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
$ZipCmd = $ENV{LOG_FILE_ZIP_CMD};
|
||||||
|
$ZipFlags = $ENV{LOG_FILE_ZIP_FLAGS};
|
||||||
|
# Provide default values for the zip command and it's flags.
|
||||||
|
if ( ! defined $ZipCmd)
|
||||||
|
{
|
||||||
|
$ZipCmd = "zip" unless defined $ZipCmd;
|
||||||
|
$ZipFlags = "-r -q" unless defined $ZipFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
process_command_line();
|
||||||
|
|
||||||
|
writeManifest();
|
||||||
|
|
||||||
|
$OUT = open_file( "content.xml" );
|
||||||
|
|
||||||
|
writeHeader();
|
||||||
|
|
||||||
|
$pathNum=0;
|
||||||
|
foreach $path (@paths)
|
||||||
|
{
|
||||||
|
writeSlideHeader($pathNum, $path->[1]);
|
||||||
|
writePath($path);
|
||||||
|
writeSlideFooter();
|
||||||
|
$pathNum++;
|
||||||
|
}
|
||||||
|
|
||||||
|
writeFooter();
|
||||||
|
|
||||||
|
$OUT->close;
|
||||||
|
|
||||||
|
zip_dirtree ($global_output_name);
|
||||||
|
|
@@ -44,38 +44,24 @@
|
|||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
class CoordinateData2D
|
struct CoordinateData2D : public basegfx::B2DPoint
|
||||||
{
|
{
|
||||||
basegfx::B2DPoint maPoint;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CoordinateData2D()
|
CoordinateData2D() {}
|
||||||
: maPoint()
|
|
||||||
{}
|
|
||||||
|
|
||||||
explicit CoordinateData2D(const basegfx::B2DPoint& rData)
|
explicit CoordinateData2D(const basegfx::B2DPoint& rData)
|
||||||
: maPoint(rData)
|
: B2DPoint(rData)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
const basegfx::B2DPoint& getCoordinate() const
|
CoordinateData2D& operator=(const basegfx::B2DPoint& rData)
|
||||||
{
|
{
|
||||||
return maPoint;
|
B2DPoint::operator=(rData);
|
||||||
}
|
return *this;
|
||||||
|
|
||||||
void setCoordinate(const basegfx::B2DPoint& rValue)
|
|
||||||
{
|
|
||||||
if(rValue != maPoint)
|
|
||||||
maPoint = rValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator==(const CoordinateData2D& rData ) const
|
|
||||||
{
|
|
||||||
return (maPoint == rData.getCoordinate());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void transform(const basegfx::B2DHomMatrix& rMatrix)
|
void transform(const basegfx::B2DHomMatrix& rMatrix)
|
||||||
{
|
{
|
||||||
maPoint *= rMatrix;
|
*this *= rMatrix;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -115,12 +101,12 @@ public:
|
|||||||
|
|
||||||
const basegfx::B2DPoint& getCoordinate(sal_uInt32 nIndex) const
|
const basegfx::B2DPoint& getCoordinate(sal_uInt32 nIndex) const
|
||||||
{
|
{
|
||||||
return maVector[nIndex].getCoordinate();
|
return maVector[nIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
void setCoordinate(sal_uInt32 nIndex, const basegfx::B2DPoint& rValue)
|
void setCoordinate(sal_uInt32 nIndex, const basegfx::B2DPoint& rValue)
|
||||||
{
|
{
|
||||||
maVector[nIndex].setCoordinate(rValue);
|
maVector[nIndex] = rValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
void insert(sal_uInt32 nIndex, const CoordinateData2D& rValue, sal_uInt32 nCount)
|
void insert(sal_uInt32 nIndex, const CoordinateData2D& rValue, sal_uInt32 nCount)
|
||||||
@@ -221,6 +207,26 @@ public:
|
|||||||
aStart->transform(rMatrix);
|
aStart->transform(rMatrix);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const basegfx::B2DPoint* begin() const
|
||||||
|
{
|
||||||
|
return &maVector.front();
|
||||||
|
}
|
||||||
|
|
||||||
|
const basegfx::B2DPoint* end() const
|
||||||
|
{
|
||||||
|
return &maVector[maVector.size()];
|
||||||
|
}
|
||||||
|
|
||||||
|
basegfx::B2DPoint* begin()
|
||||||
|
{
|
||||||
|
return &maVector.front();
|
||||||
|
}
|
||||||
|
|
||||||
|
basegfx::B2DPoint* end()
|
||||||
|
{
|
||||||
|
return &maVector[maVector.size()];
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -1113,6 +1119,28 @@ public:
|
|||||||
maPoints.transform(rMatrix);
|
maPoints.transform(rMatrix);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const basegfx::B2DPoint* begin() const
|
||||||
|
{
|
||||||
|
return maPoints.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
const basegfx::B2DPoint* end() const
|
||||||
|
{
|
||||||
|
return maPoints.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
basegfx::B2DPoint* begin()
|
||||||
|
{
|
||||||
|
mpBufferedData.reset();
|
||||||
|
return maPoints.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
basegfx::B2DPoint* end()
|
||||||
|
{
|
||||||
|
mpBufferedData.reset();
|
||||||
|
return maPoints.end();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -1173,7 +1201,7 @@ namespace basegfx
|
|||||||
return mpPolygon->count();
|
return mpPolygon->count();
|
||||||
}
|
}
|
||||||
|
|
||||||
B2DPoint B2DPolygon::getB2DPoint(sal_uInt32 nIndex) const
|
const B2DPoint& B2DPolygon::getB2DPoint(sal_uInt32 nIndex) const
|
||||||
{
|
{
|
||||||
OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
|
OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
|
||||||
|
|
||||||
@@ -1432,7 +1460,7 @@ namespace basegfx
|
|||||||
return mpPolygon->getDefaultAdaptiveSubdivision(*this);
|
return mpPolygon->getDefaultAdaptiveSubdivision(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
B2DRange B2DPolygon::getB2DRange() const
|
const B2DRange& B2DPolygon::getB2DRange() const
|
||||||
{
|
{
|
||||||
return mpPolygon->getB2DRange(*this);
|
return mpPolygon->getB2DRange(*this);
|
||||||
}
|
}
|
||||||
@@ -1540,6 +1568,26 @@ namespace basegfx
|
|||||||
mpPolygon->transform(rMatrix);
|
mpPolygon->transform(rMatrix);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const B2DPoint* B2DPolygon::begin() const
|
||||||
|
{
|
||||||
|
return mpPolygon->begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
const B2DPoint* B2DPolygon::end() const
|
||||||
|
{
|
||||||
|
return mpPolygon->end();
|
||||||
|
}
|
||||||
|
|
||||||
|
B2DPoint* B2DPolygon::begin()
|
||||||
|
{
|
||||||
|
return mpPolygon->begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
B2DPoint* B2DPolygon::end()
|
||||||
|
{
|
||||||
|
return mpPolygon->end();
|
||||||
|
}
|
||||||
} // end of namespace basegfx
|
} // end of namespace basegfx
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
@@ -166,6 +166,26 @@ public:
|
|||||||
maPolygons.end(),
|
maPolygons.end(),
|
||||||
std::mem_fun_ref( &basegfx::B2DPolygon::makeUnique ));
|
std::mem_fun_ref( &basegfx::B2DPolygon::makeUnique ));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const basegfx::B2DPolygon* begin() const
|
||||||
|
{
|
||||||
|
return &maPolygons.front();
|
||||||
|
}
|
||||||
|
|
||||||
|
const basegfx::B2DPolygon* end() const
|
||||||
|
{
|
||||||
|
return &maPolygons[maPolygons.size()];
|
||||||
|
}
|
||||||
|
|
||||||
|
basegfx::B2DPolygon* begin()
|
||||||
|
{
|
||||||
|
return &maPolygons.front();
|
||||||
|
}
|
||||||
|
|
||||||
|
basegfx::B2DPolygon* end()
|
||||||
|
{
|
||||||
|
return &maPolygons[maPolygons.size()];
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -378,6 +398,26 @@ namespace basegfx
|
|||||||
mpPolyPolygon->transform(rMatrix);
|
mpPolyPolygon->transform(rMatrix);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const B2DPolygon* B2DPolyPolygon::begin() const
|
||||||
|
{
|
||||||
|
return mpPolyPolygon->begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
const B2DPolygon* B2DPolyPolygon::end() const
|
||||||
|
{
|
||||||
|
return mpPolyPolygon->end();
|
||||||
|
}
|
||||||
|
|
||||||
|
B2DPolygon* B2DPolyPolygon::begin()
|
||||||
|
{
|
||||||
|
return mpPolyPolygon->begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
B2DPolygon* B2DPolyPolygon::end()
|
||||||
|
{
|
||||||
|
return mpPolyPolygon->end();
|
||||||
|
}
|
||||||
} // end of namespace basegfx
|
} // end of namespace basegfx
|
||||||
|
|
||||||
// eof
|
// eof
|
||||||
|
@@ -1,282 +0,0 @@
|
|||||||
/*************************************************************************
|
|
||||||
*
|
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
||||||
*
|
|
||||||
* Copyright 2008 by Sun Microsystems, Inc.
|
|
||||||
*
|
|
||||||
* OpenOffice.org - a multi-platform office productivity suite
|
|
||||||
*
|
|
||||||
* $RCSfile: b2dmultirange.cxx,v $
|
|
||||||
* $Revision: 1.8 $
|
|
||||||
*
|
|
||||||
* 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
|
|
371
basegfx/source/range/b2dpolyrange.cxx
Normal file
371
basegfx/source/range/b2dpolyrange.cxx
Normal file
@@ -0,0 +1,371 @@
|
|||||||
|
/*************************************************************************
|
||||||
|
*
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* Copyright 2008 by Sun Microsystems, Inc.
|
||||||
|
*
|
||||||
|
* OpenOffice.org - a multi-platform office productivity suite
|
||||||
|
*
|
||||||
|
* $RCSfile: b2dmultirange.cxx,v $
|
||||||
|
* $Revision: 1.8 $
|
||||||
|
*
|
||||||
|
* 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/b2dpolyrange.hxx>
|
||||||
|
|
||||||
|
#include <basegfx/range/b2drange.hxx>
|
||||||
|
#include <basegfx/range/b2drangeclipper.hxx>
|
||||||
|
#include <basegfx/tuple/b2dtuple.hxx>
|
||||||
|
#include <basegfx/polygon/b2dpolypolygon.hxx>
|
||||||
|
|
||||||
|
#include <boost/bind.hpp>
|
||||||
|
#include <boost/tuple/tuple.hpp>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
static basegfx::B2VectorOrientation flipOrientation(
|
||||||
|
basegfx::B2VectorOrientation eOrient)
|
||||||
|
{
|
||||||
|
return eOrient == basegfx::ORIENTATION_POSITIVE ?
|
||||||
|
basegfx::ORIENTATION_NEGATIVE : basegfx::ORIENTATION_POSITIVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace basegfx
|
||||||
|
{
|
||||||
|
class ImplB2DPolyRange
|
||||||
|
{
|
||||||
|
void updateBounds()
|
||||||
|
{
|
||||||
|
maBounds.reset();
|
||||||
|
std::for_each(maRanges.begin(),
|
||||||
|
maRanges.end(),
|
||||||
|
boost::bind(
|
||||||
|
(void (B2DRange::*)(const B2DRange&))(
|
||||||
|
&B2DRange::expand),
|
||||||
|
boost::ref(maBounds),
|
||||||
|
_1));
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
ImplB2DPolyRange() :
|
||||||
|
maBounds(),
|
||||||
|
maRanges(),
|
||||||
|
maOrient()
|
||||||
|
{}
|
||||||
|
|
||||||
|
explicit ImplB2DPolyRange( const B2DPolyRange::ElementType& rElem ) :
|
||||||
|
maBounds( boost::get<0>(rElem) ),
|
||||||
|
maRanges( 1, boost::get<0>(rElem) ),
|
||||||
|
maOrient( 1, boost::get<1>(rElem) )
|
||||||
|
{}
|
||||||
|
|
||||||
|
explicit ImplB2DPolyRange( const B2DRange& rRange, B2VectorOrientation eOrient ) :
|
||||||
|
maBounds( rRange ),
|
||||||
|
maRanges( 1, rRange ),
|
||||||
|
maOrient( 1, eOrient )
|
||||||
|
{}
|
||||||
|
|
||||||
|
bool operator==(const ImplB2DPolyRange& rRHS) const
|
||||||
|
{
|
||||||
|
return maRanges == rRHS.maRanges && maOrient == rRHS.maOrient;
|
||||||
|
}
|
||||||
|
|
||||||
|
sal_uInt32 count() const
|
||||||
|
{
|
||||||
|
return maRanges.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
B2DPolyRange::ElementType getElement(sal_uInt32 nIndex) const
|
||||||
|
{
|
||||||
|
return boost::make_tuple(maRanges[nIndex],
|
||||||
|
maOrient[nIndex]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setElement(sal_uInt32 nIndex, const B2DPolyRange::ElementType& rElement )
|
||||||
|
{
|
||||||
|
maRanges[nIndex] = boost::get<0>(rElement);
|
||||||
|
maOrient[nIndex] = boost::get<1>(rElement);
|
||||||
|
updateBounds();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setElement(sal_uInt32 nIndex, const B2DRange& rRange, B2VectorOrientation eOrient )
|
||||||
|
{
|
||||||
|
maRanges[nIndex] = rRange;
|
||||||
|
maOrient[nIndex] = eOrient;
|
||||||
|
updateBounds();
|
||||||
|
}
|
||||||
|
|
||||||
|
void insertElement(sal_uInt32 nIndex, const B2DPolyRange::ElementType& rElement, sal_uInt32 nCount)
|
||||||
|
{
|
||||||
|
maRanges.insert(maRanges.begin()+nIndex, nCount, boost::get<0>(rElement));
|
||||||
|
maOrient.insert(maOrient.begin()+nIndex, nCount, boost::get<1>(rElement));
|
||||||
|
maBounds.expand(boost::get<0>(rElement));
|
||||||
|
}
|
||||||
|
|
||||||
|
void insertElement(sal_uInt32 nIndex, const B2DRange& rRange, B2VectorOrientation eOrient, sal_uInt32 nCount)
|
||||||
|
{
|
||||||
|
maRanges.insert(maRanges.begin()+nIndex, nCount, rRange);
|
||||||
|
maOrient.insert(maOrient.begin()+nIndex, nCount, eOrient);
|
||||||
|
maBounds.expand(rRange);
|
||||||
|
}
|
||||||
|
|
||||||
|
void appendElement(const B2DPolyRange::ElementType& rElement, sal_uInt32 nCount)
|
||||||
|
{
|
||||||
|
maRanges.insert(maRanges.end(), nCount, boost::get<0>(rElement));
|
||||||
|
maOrient.insert(maOrient.end(), nCount, boost::get<1>(rElement));
|
||||||
|
maBounds.expand(boost::get<0>(rElement));
|
||||||
|
}
|
||||||
|
|
||||||
|
void appendElement(const B2DRange& rRange, B2VectorOrientation eOrient, sal_uInt32 nCount)
|
||||||
|
{
|
||||||
|
maRanges.insert(maRanges.end(), nCount, rRange);
|
||||||
|
maOrient.insert(maOrient.end(), nCount, eOrient);
|
||||||
|
maBounds.expand(rRange);
|
||||||
|
}
|
||||||
|
|
||||||
|
void insertPolyRange(sal_uInt32 nIndex, const ImplB2DPolyRange& rPolyRange)
|
||||||
|
{
|
||||||
|
maRanges.insert(maRanges.begin()+nIndex, rPolyRange.maRanges.begin(), rPolyRange.maRanges.end());
|
||||||
|
maOrient.insert(maOrient.begin()+nIndex, rPolyRange.maOrient.begin(), rPolyRange.maOrient.end());
|
||||||
|
updateBounds();
|
||||||
|
}
|
||||||
|
|
||||||
|
void appendPolyRange(const ImplB2DPolyRange& rPolyRange)
|
||||||
|
{
|
||||||
|
maRanges.insert(maRanges.end(),
|
||||||
|
rPolyRange.maRanges.begin(),
|
||||||
|
rPolyRange.maRanges.end());
|
||||||
|
maOrient.insert(maOrient.end(),
|
||||||
|
rPolyRange.maOrient.begin(),
|
||||||
|
rPolyRange.maOrient.end());
|
||||||
|
updateBounds();
|
||||||
|
}
|
||||||
|
|
||||||
|
void remove(sal_uInt32 nIndex, sal_uInt32 nCount)
|
||||||
|
{
|
||||||
|
maRanges.erase(maRanges.begin()+nIndex,maRanges.begin()+nIndex+nCount);
|
||||||
|
maOrient.erase(maOrient.begin()+nIndex,maOrient.begin()+nIndex+nCount);
|
||||||
|
updateBounds();
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
std::vector<B2DRange> aTmpRanges;
|
||||||
|
std::vector<B2VectorOrientation> aTmpOrient;
|
||||||
|
|
||||||
|
maRanges.swap(aTmpRanges);
|
||||||
|
maOrient.swap(aTmpOrient);
|
||||||
|
|
||||||
|
maBounds.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void flip()
|
||||||
|
{
|
||||||
|
std::for_each(maOrient.begin(),
|
||||||
|
maOrient.end(),
|
||||||
|
boost::bind(
|
||||||
|
&flipOrientation,
|
||||||
|
_1));
|
||||||
|
}
|
||||||
|
|
||||||
|
B2DRange getBounds() const
|
||||||
|
{
|
||||||
|
return maBounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
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.
|
||||||
|
std::vector<B2DRange>::const_iterator aCurr( maRanges.begin() );
|
||||||
|
const std::vector<B2DRange>::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 std::vector<B2DRange>::const_iterator aEnd( maRanges.end() );
|
||||||
|
return std::find_if( maRanges.begin(),
|
||||||
|
aEnd,
|
||||||
|
boost::bind<bool>( boost::mem_fn( &B2DRange::overlaps ),
|
||||||
|
_1,
|
||||||
|
boost::cref(rRange) ) ) != aEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
B2DPolyPolygon solveCrossovers() const
|
||||||
|
{
|
||||||
|
return tools::solveCrossovers(maRanges,maOrient);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
B2DRange maBounds;
|
||||||
|
std::vector<B2DRange> maRanges;
|
||||||
|
std::vector<B2VectorOrientation> maOrient;
|
||||||
|
};
|
||||||
|
|
||||||
|
B2DPolyRange::B2DPolyRange() :
|
||||||
|
mpImpl()
|
||||||
|
{}
|
||||||
|
|
||||||
|
B2DPolyRange::~B2DPolyRange()
|
||||||
|
{}
|
||||||
|
|
||||||
|
B2DPolyRange::B2DPolyRange( const ElementType& rElem ) :
|
||||||
|
mpImpl( ImplB2DPolyRange( rElem ) )
|
||||||
|
{}
|
||||||
|
|
||||||
|
B2DPolyRange::B2DPolyRange( const B2DRange& rRange, B2VectorOrientation eOrient ) :
|
||||||
|
mpImpl( ImplB2DPolyRange( rRange, eOrient ) )
|
||||||
|
{}
|
||||||
|
|
||||||
|
B2DPolyRange::B2DPolyRange( const B2DPolyRange& rRange ) :
|
||||||
|
mpImpl( rRange.mpImpl )
|
||||||
|
{}
|
||||||
|
|
||||||
|
B2DPolyRange& B2DPolyRange::operator=( const B2DPolyRange& rRange )
|
||||||
|
{
|
||||||
|
mpImpl = rRange.mpImpl;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void B2DPolyRange::makeUnique()
|
||||||
|
{
|
||||||
|
mpImpl.make_unique();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool B2DPolyRange::operator==(const B2DPolyRange& rRange) const
|
||||||
|
{
|
||||||
|
if(mpImpl.same_object(rRange.mpImpl))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return ((*mpImpl) == (*rRange.mpImpl));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool B2DPolyRange::operator!=(const B2DPolyRange& rRange) const
|
||||||
|
{
|
||||||
|
return !(*this == rRange);
|
||||||
|
}
|
||||||
|
|
||||||
|
sal_uInt32 B2DPolyRange::count() const
|
||||||
|
{
|
||||||
|
return mpImpl->count();
|
||||||
|
}
|
||||||
|
|
||||||
|
B2DPolyRange::ElementType B2DPolyRange::getElement(sal_uInt32 nIndex) const
|
||||||
|
{
|
||||||
|
return mpImpl->getElement(nIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void B2DPolyRange::setElement(sal_uInt32 nIndex, const ElementType& rElement )
|
||||||
|
{
|
||||||
|
mpImpl->setElement(nIndex, rElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
void B2DPolyRange::setElement(sal_uInt32 nIndex, const B2DRange& rRange, B2VectorOrientation eOrient )
|
||||||
|
{
|
||||||
|
mpImpl->setElement(nIndex, rRange, eOrient );
|
||||||
|
}
|
||||||
|
|
||||||
|
void B2DPolyRange::insertElement(sal_uInt32 nIndex, const ElementType& rElement, sal_uInt32 nCount)
|
||||||
|
{
|
||||||
|
mpImpl->insertElement(nIndex, rElement, nCount );
|
||||||
|
}
|
||||||
|
|
||||||
|
void B2DPolyRange::insertElement(sal_uInt32 nIndex, const B2DRange& rRange, B2VectorOrientation eOrient, sal_uInt32 nCount)
|
||||||
|
{
|
||||||
|
mpImpl->insertElement(nIndex, rRange, eOrient, nCount );
|
||||||
|
}
|
||||||
|
|
||||||
|
void B2DPolyRange::appendElement(const ElementType& rElement, sal_uInt32 nCount)
|
||||||
|
{
|
||||||
|
mpImpl->appendElement(rElement, nCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
void B2DPolyRange::appendElement(const B2DRange& rRange, B2VectorOrientation eOrient, sal_uInt32 nCount)
|
||||||
|
{
|
||||||
|
mpImpl->appendElement(rRange, eOrient, nCount );
|
||||||
|
}
|
||||||
|
|
||||||
|
void B2DPolyRange::insertPolyRange(sal_uInt32 nIndex, const B2DPolyRange& rRange)
|
||||||
|
{
|
||||||
|
mpImpl->insertPolyRange(nIndex, *rRange.mpImpl);
|
||||||
|
}
|
||||||
|
|
||||||
|
void B2DPolyRange::appendPolyRange(const B2DPolyRange& rRange)
|
||||||
|
{
|
||||||
|
mpImpl->appendPolyRange(*rRange.mpImpl);
|
||||||
|
}
|
||||||
|
|
||||||
|
void B2DPolyRange::remove(sal_uInt32 nIndex, sal_uInt32 nCount)
|
||||||
|
{
|
||||||
|
mpImpl->remove(nIndex, nCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
void B2DPolyRange::clear()
|
||||||
|
{
|
||||||
|
mpImpl->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void B2DPolyRange::flip()
|
||||||
|
{
|
||||||
|
mpImpl->flip();
|
||||||
|
}
|
||||||
|
|
||||||
|
B2DRange B2DPolyRange::getBounds() const
|
||||||
|
{
|
||||||
|
return mpImpl->getBounds();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool B2DPolyRange::isInside( const B2DTuple& rTuple ) const
|
||||||
|
{
|
||||||
|
return mpImpl->isInside(rTuple);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool B2DPolyRange::isInside( const B2DRange& rRange ) const
|
||||||
|
{
|
||||||
|
return mpImpl->isInside(rRange);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool B2DPolyRange::overlaps( const B2DRange& rRange ) const
|
||||||
|
{
|
||||||
|
return mpImpl->overlaps(rRange);
|
||||||
|
}
|
||||||
|
|
||||||
|
B2DPolyPolygon B2DPolyRange::solveCrossovers() const
|
||||||
|
{
|
||||||
|
return mpImpl->solveCrossovers();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end of namespace basegfx
|
||||||
|
|
||||||
|
// eof
|
950
basegfx/source/range/b2drangeclipper.cxx
Normal file
950
basegfx/source/range/b2drangeclipper.cxx
Normal file
@@ -0,0 +1,950 @@
|
|||||||
|
/*************************************************************************
|
||||||
|
*
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* Copyright 2008 by Sun Microsystems, Inc.
|
||||||
|
*
|
||||||
|
* OpenOffice.org - a multi-platform office productivity suite
|
||||||
|
*
|
||||||
|
* $RCSfile: b2dmultirange.cxx,v $
|
||||||
|
* $Revision: 1.8 $
|
||||||
|
*
|
||||||
|
* 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 <rtl/math.hxx>
|
||||||
|
|
||||||
|
#include <basegfx/tuple/b2dtuple.hxx>
|
||||||
|
#include <basegfx/range/b2drange.hxx>
|
||||||
|
#include <basegfx/range/b2dpolyrange.hxx>
|
||||||
|
#include <basegfx/polygon/b2dpolypolygon.hxx>
|
||||||
|
#include <basegfx/polygon/b2dpolygontools.hxx>
|
||||||
|
#include <basegfx/polygon/b2dpolypolygontools.hxx>
|
||||||
|
|
||||||
|
#include <o3tl/vector_pool.hxx>
|
||||||
|
#include <boost/bind.hpp>
|
||||||
|
#include <boost/utility.hpp>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <deque>
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
|
||||||
|
namespace basegfx
|
||||||
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
// Generating a poly-polygon from a bunch of rectangles
|
||||||
|
//
|
||||||
|
// Helper functionality for sweep-line algorithm
|
||||||
|
// ====================================================
|
||||||
|
|
||||||
|
typedef std::vector<B2DRange> VectorOfRanges;
|
||||||
|
|
||||||
|
class ImplPolygon;
|
||||||
|
typedef o3tl::vector_pool<ImplPolygon> VectorOfPolygons;
|
||||||
|
|
||||||
|
|
||||||
|
/** This class represents an active edge
|
||||||
|
|
||||||
|
As the sweep line traverses across the overall area,
|
||||||
|
rectangle edges parallel to it generate events, and
|
||||||
|
rectangle edges orthogonal to it generate active
|
||||||
|
edges. This class represents the latter.
|
||||||
|
*/
|
||||||
|
class ActiveEdge
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/** The two possible active rectangle edges differ by one
|
||||||
|
coordinate value - the upper edge has the lower, the
|
||||||
|
lower edge the higher value.
|
||||||
|
*/
|
||||||
|
enum EdgeType {
|
||||||
|
/// edge with lower coordinate value
|
||||||
|
UPPER=0,
|
||||||
|
/// edge with higher coordinate value
|
||||||
|
LOWER=1
|
||||||
|
};
|
||||||
|
|
||||||
|
enum EdgeDirection {
|
||||||
|
/// edge proceeds to the left
|
||||||
|
PROCEED_LEFT=0,
|
||||||
|
/// edge proceeds to the right
|
||||||
|
PROCEED_RIGHT=1
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Create active edge
|
||||||
|
|
||||||
|
@param rRect
|
||||||
|
Rectangle this edge is part of
|
||||||
|
|
||||||
|
@param fInvariantCoord
|
||||||
|
The invariant ccordinate value of this edge
|
||||||
|
|
||||||
|
@param eEdgeType
|
||||||
|
Is fInvariantCoord the lower or the higher value, for
|
||||||
|
this rect?
|
||||||
|
*/
|
||||||
|
ActiveEdge( const B2DRectangle& rRect,
|
||||||
|
const double& fInvariantCoord,
|
||||||
|
std::ptrdiff_t nPolyIdx,
|
||||||
|
EdgeType eEdgeType,
|
||||||
|
EdgeDirection eEdgeDirection ) :
|
||||||
|
mfInvariantCoord(fInvariantCoord),
|
||||||
|
mpAssociatedRect( &rRect ),
|
||||||
|
mnPolygonIdx( nPolyIdx ),
|
||||||
|
meEdgeType( eEdgeType ),
|
||||||
|
meEdgeDirection( eEdgeDirection )
|
||||||
|
{}
|
||||||
|
|
||||||
|
double getInvariantCoord() const { return mfInvariantCoord; }
|
||||||
|
const B2DRectangle& getRect() const { return *mpAssociatedRect; }
|
||||||
|
std::ptrdiff_t getTargetPolygonIndex() const { return mnPolygonIdx; }
|
||||||
|
void setTargetPolygonIndex( std::ptrdiff_t nIdx ) { mnPolygonIdx = nIdx; }
|
||||||
|
EdgeType getEdgeType() const { return meEdgeType; }
|
||||||
|
EdgeDirection getEdgeDirection() const { return meEdgeDirection; }
|
||||||
|
|
||||||
|
/// For STL sort
|
||||||
|
bool operator<( const ActiveEdge& rRHS ) const { return mfInvariantCoord < rRHS.mfInvariantCoord; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
/** The invariant coordinate value of this edge (e.g. the
|
||||||
|
common y value, for a horizontal edge)
|
||||||
|
*/
|
||||||
|
double mfInvariantCoord;
|
||||||
|
|
||||||
|
/** Associated rectangle
|
||||||
|
|
||||||
|
This on the one hand saves some storage space (the
|
||||||
|
vector of rectangles is persistent, anyway), and on
|
||||||
|
the other hand provides an identifier to match active
|
||||||
|
edges and x events (see below)
|
||||||
|
|
||||||
|
Ptr because class needs to be assignable
|
||||||
|
*/
|
||||||
|
const B2DRectangle* mpAssociatedRect;
|
||||||
|
|
||||||
|
/** Index of the polygon this edge is currently involved
|
||||||
|
with.
|
||||||
|
|
||||||
|
Note that this can change for some kinds of edge
|
||||||
|
intersection, as the algorithm tends to swap
|
||||||
|
associated polygons there.
|
||||||
|
|
||||||
|
-1 denotes no assigned polygon
|
||||||
|
*/
|
||||||
|
std::ptrdiff_t mnPolygonIdx;
|
||||||
|
|
||||||
|
/// 'upper' or 'lower' edge of original rectangle.
|
||||||
|
EdgeType meEdgeType;
|
||||||
|
|
||||||
|
/// 'left' or 'right'
|
||||||
|
EdgeDirection meEdgeDirection;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Needs to be list - various places hold ptrs to elements
|
||||||
|
typedef std::list< ActiveEdge > ListOfEdges;
|
||||||
|
|
||||||
|
|
||||||
|
/** Element of the sweep line event list
|
||||||
|
|
||||||
|
As the sweep line traverses across the overall area,
|
||||||
|
rectangle edges parallel to it generate events, and
|
||||||
|
rectangle edges orthogonal to it generate active
|
||||||
|
edges. This class represents the former.
|
||||||
|
|
||||||
|
The class defines an element of the sweep line list. The
|
||||||
|
sweep line's position jumps in steps defined by the
|
||||||
|
coordinates of the sorted SweepLineEvent entries.
|
||||||
|
*/
|
||||||
|
class SweepLineEvent
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/** The two possible sweep line rectangle edges differ by
|
||||||
|
one coordinate value - the starting edge has the
|
||||||
|
lower, the finishing edge the higher value.
|
||||||
|
*/
|
||||||
|
enum EdgeType {
|
||||||
|
/// edge with lower coordinate value
|
||||||
|
STARTING_EDGE=0,
|
||||||
|
/// edge with higher coordinate value
|
||||||
|
FINISHING_EDGE=1
|
||||||
|
};
|
||||||
|
|
||||||
|
/** The two possible sweep line directions
|
||||||
|
*/
|
||||||
|
enum EdgeDirection {
|
||||||
|
PROCEED_UP=0,
|
||||||
|
PROCEED_DOWN=1
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Create sweep line event
|
||||||
|
|
||||||
|
@param fPos
|
||||||
|
Coordinate position of the event
|
||||||
|
|
||||||
|
@param rRect
|
||||||
|
Rectangle this event is generated for.
|
||||||
|
|
||||||
|
@param eEdgeType
|
||||||
|
Is fPos the lower or the higher value, for the
|
||||||
|
rectangle this event is generated for?
|
||||||
|
*/
|
||||||
|
SweepLineEvent( double fPos,
|
||||||
|
const B2DRectangle& rRect,
|
||||||
|
EdgeType eEdgeType,
|
||||||
|
EdgeDirection eDirection) :
|
||||||
|
mfPos( fPos ),
|
||||||
|
mpAssociatedRect( &rRect ),
|
||||||
|
meEdgeType( eEdgeType ),
|
||||||
|
meEdgeDirection( eDirection )
|
||||||
|
{}
|
||||||
|
|
||||||
|
double getPos() const { return mfPos; }
|
||||||
|
const B2DRectangle& getRect() const { return *mpAssociatedRect; }
|
||||||
|
EdgeType getEdgeType() const { return meEdgeType; }
|
||||||
|
EdgeDirection getEdgeDirection() const { return meEdgeDirection; }
|
||||||
|
|
||||||
|
/// For STL sort
|
||||||
|
bool operator<( const SweepLineEvent& rRHS ) const { return mfPos < rRHS.mfPos; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// position of the event, in the direction of the line sweep
|
||||||
|
double mfPos;
|
||||||
|
|
||||||
|
/** Rectangle this event is generated for
|
||||||
|
|
||||||
|
This on the one hand saves some storage space (the
|
||||||
|
vector of rectangles is persistent, anyway), and on
|
||||||
|
the other hand provides an identifier to match active
|
||||||
|
edges and events (see below)
|
||||||
|
|
||||||
|
Ptr because class needs to be assignable
|
||||||
|
*/
|
||||||
|
const B2DRectangle* mpAssociatedRect;
|
||||||
|
|
||||||
|
/// 'upper' or 'lower' edge of original rectangle.
|
||||||
|
EdgeType meEdgeType;
|
||||||
|
|
||||||
|
/// 'up' or 'down'
|
||||||
|
EdgeDirection meEdgeDirection;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::vector< SweepLineEvent > VectorOfEvents;
|
||||||
|
|
||||||
|
|
||||||
|
/** Smart point container for B2DMultiRange::getPolyPolygon()
|
||||||
|
|
||||||
|
This class provides methods needed only here, and is used
|
||||||
|
as a place to store some additional information per
|
||||||
|
polygon. Also, most of the intersection logic is
|
||||||
|
implemented here.
|
||||||
|
*/
|
||||||
|
class ImplPolygon
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/** Create polygon
|
||||||
|
*/
|
||||||
|
ImplPolygon() :
|
||||||
|
mpLeadingRightEdge(NULL),
|
||||||
|
mnIdx(-1),
|
||||||
|
maPoints(),
|
||||||
|
mbIsFinished(false)
|
||||||
|
{
|
||||||
|
// completely ad-hoc. but what the hell.
|
||||||
|
maPoints.reserve(11);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setPolygonPoolIndex( std::ptrdiff_t nIdx ) { mnIdx = nIdx; }
|
||||||
|
bool isFinished() const { return mbIsFinished; }
|
||||||
|
|
||||||
|
/// Add point to the end of the existing points
|
||||||
|
void append( const B2DPoint& rPoint )
|
||||||
|
{
|
||||||
|
OSL_PRECOND( maPoints.empty() ||
|
||||||
|
maPoints.back().getX() == rPoint.getX() ||
|
||||||
|
maPoints.back().getY() == rPoint.getY(),
|
||||||
|
"ImplPolygon::append(): added point violates 90 degree line angle constraint!" );
|
||||||
|
|
||||||
|
if( maPoints.empty() ||
|
||||||
|
maPoints.back() != rPoint )
|
||||||
|
{
|
||||||
|
// avoid duplicate points
|
||||||
|
maPoints.push_back( rPoint );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Perform the intersection of this polygon with an
|
||||||
|
active edge.
|
||||||
|
|
||||||
|
@param rEvent
|
||||||
|
The vertical line event that generated the
|
||||||
|
intersection
|
||||||
|
|
||||||
|
@param rActiveEdge
|
||||||
|
The active edge that generated the intersection
|
||||||
|
|
||||||
|
@param rPolygonPool
|
||||||
|
Polygon pool, we sometimes need to allocate a new one
|
||||||
|
|
||||||
|
@param bIsFinishingEdge
|
||||||
|
True, when this is hitting the last edge of the
|
||||||
|
vertical sweep - every vertical sweep starts and ends
|
||||||
|
with upper and lower edge of the _same_ rectangle.
|
||||||
|
|
||||||
|
@return the new current polygon (that's the one
|
||||||
|
processing must proceed with, when going through the
|
||||||
|
list of upcoming active edges).
|
||||||
|
*/
|
||||||
|
std::ptrdiff_t intersect( SweepLineEvent& rEvent,
|
||||||
|
ActiveEdge& rActiveEdge,
|
||||||
|
VectorOfPolygons& rPolygonPool,
|
||||||
|
B2DPolyPolygon& rRes,
|
||||||
|
bool isFinishingEdge )
|
||||||
|
{
|
||||||
|
OSL_PRECOND( !isFinished(),
|
||||||
|
"ImplPolygon::intersect(): called on already finished polygon!" );
|
||||||
|
OSL_PRECOND( !isFinishingEdge
|
||||||
|
|| (isFinishingEdge && &rEvent.getRect() == &rActiveEdge.getRect()),
|
||||||
|
"ImplPolygon::intersect(): inconsistent ending!" );
|
||||||
|
|
||||||
|
const B2DPoint aIntersectionPoint( rEvent.getPos(),
|
||||||
|
rActiveEdge.getInvariantCoord() );
|
||||||
|
|
||||||
|
// intersection point, goes to our polygon
|
||||||
|
// unconditionally
|
||||||
|
append(aIntersectionPoint);
|
||||||
|
|
||||||
|
const bool isSweepLineEnteringRect(
|
||||||
|
rEvent.getEdgeType() == SweepLineEvent::STARTING_EDGE);
|
||||||
|
if( isFinishingEdge )
|
||||||
|
{
|
||||||
|
if( isSweepLineEnteringRect )
|
||||||
|
handleFinalOwnRightEdge(rActiveEdge);
|
||||||
|
else
|
||||||
|
handleFinalOwnLeftEdge(rActiveEdge,
|
||||||
|
rPolygonPool,
|
||||||
|
rRes);
|
||||||
|
|
||||||
|
// we're done with this rect & sweep line
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else if( metOwnEdge(rEvent,rActiveEdge) )
|
||||||
|
{
|
||||||
|
handleInitialOwnEdge(rEvent, rActiveEdge);
|
||||||
|
|
||||||
|
// point already added, all init done, continue
|
||||||
|
// with same poly
|
||||||
|
return mnIdx;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
OSL_ENSURE( rActiveEdge.getTargetPolygonIndex() != -1,
|
||||||
|
"ImplPolygon::intersect(): non-trivial intersection hit empty polygon!" );
|
||||||
|
|
||||||
|
const bool isHittingLeftEdge(
|
||||||
|
rActiveEdge.getEdgeDirection() == ActiveEdge::PROCEED_LEFT);
|
||||||
|
|
||||||
|
if( isHittingLeftEdge )
|
||||||
|
return handleComplexLeftEdge(rActiveEdge,
|
||||||
|
aIntersectionPoint,
|
||||||
|
rPolygonPool,
|
||||||
|
rRes);
|
||||||
|
else
|
||||||
|
return handleComplexRightEdge(rActiveEdge,
|
||||||
|
aIntersectionPoint,
|
||||||
|
rPolygonPool);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::ptrdiff_t getPolygonPoolIndex() const { return mnIdx; }
|
||||||
|
|
||||||
|
void handleInitialOwnEdge(SweepLineEvent& rEvent,
|
||||||
|
ActiveEdge& rActiveEdge)
|
||||||
|
{
|
||||||
|
const bool isActiveEdgeProceedLeft(
|
||||||
|
rActiveEdge.getEdgeDirection() == ActiveEdge::PROCEED_LEFT);
|
||||||
|
const bool isSweepLineEnteringRect(
|
||||||
|
rEvent.getEdgeType() == SweepLineEvent::STARTING_EDGE);
|
||||||
|
(void)isActiveEdgeProceedLeft;
|
||||||
|
(void)isSweepLineEnteringRect;
|
||||||
|
|
||||||
|
OSL_ENSURE( isSweepLineEnteringRect == isActiveEdgeProceedLeft,
|
||||||
|
"ImplPolygon::intersect(): sweep initial own edge hit: wrong polygon order" );
|
||||||
|
|
||||||
|
OSL_ENSURE( isSweepLineEnteringRect ||
|
||||||
|
mpLeadingRightEdge == &rActiveEdge,
|
||||||
|
"ImplPolygon::intersect(): sweep initial own edge hit: wrong leading edge" );
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleFinalOwnRightEdge(ActiveEdge& rActiveEdge)
|
||||||
|
{
|
||||||
|
OSL_ENSURE( rActiveEdge.getEdgeDirection() == ActiveEdge::PROCEED_RIGHT,
|
||||||
|
"ImplPolygon::handleInitialOwnRightEdge(): start edge wrong polygon order" );
|
||||||
|
|
||||||
|
rActiveEdge.setTargetPolygonIndex(mnIdx);
|
||||||
|
mpLeadingRightEdge = &rActiveEdge;
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleFinalOwnLeftEdge(ActiveEdge& rActiveEdge,
|
||||||
|
VectorOfPolygons& rPolygonPool,
|
||||||
|
B2DPolyPolygon& rRes)
|
||||||
|
{
|
||||||
|
OSL_ENSURE( rActiveEdge.getEdgeDirection() == ActiveEdge::PROCEED_LEFT,
|
||||||
|
"ImplPolygon::handleFinalOwnLeftEdge(): end edge wrong polygon order" );
|
||||||
|
|
||||||
|
const bool isHittingOurTail(
|
||||||
|
rActiveEdge.getTargetPolygonIndex() == mnIdx);
|
||||||
|
|
||||||
|
if( isHittingOurTail )
|
||||||
|
finish(rRes); // just finish. no fuss.
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// temp poly hits final left edge
|
||||||
|
const std::ptrdiff_t nTmpIdx=rActiveEdge.getTargetPolygonIndex();
|
||||||
|
ImplPolygon& rTmp=rPolygonPool.get(nTmpIdx);
|
||||||
|
|
||||||
|
// active edge's polygon has points
|
||||||
|
// already. ours need to go in front of them.
|
||||||
|
maPoints.insert(maPoints.end(),
|
||||||
|
rTmp.maPoints.begin(),
|
||||||
|
rTmp.maPoints.end());
|
||||||
|
|
||||||
|
// adjust leading edges, we're switching the polygon
|
||||||
|
ActiveEdge* const pFarEdge=rTmp.mpLeadingRightEdge;
|
||||||
|
|
||||||
|
mpLeadingRightEdge = pFarEdge;
|
||||||
|
pFarEdge->setTargetPolygonIndex(mnIdx);
|
||||||
|
|
||||||
|
// nTmpIdx is an empty shell, get rid of it
|
||||||
|
rPolygonPool.free(nTmpIdx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ptrdiff_t handleComplexLeftEdge(ActiveEdge& rActiveEdge,
|
||||||
|
const B2DPoint& rIntersectionPoint,
|
||||||
|
VectorOfPolygons& rPolygonPool,
|
||||||
|
B2DPolyPolygon& rRes)
|
||||||
|
{
|
||||||
|
const bool isHittingOurTail(
|
||||||
|
rActiveEdge.getTargetPolygonIndex() == mnIdx);
|
||||||
|
if( isHittingOurTail )
|
||||||
|
{
|
||||||
|
finish(rRes);
|
||||||
|
|
||||||
|
// so "this" is done - need new polygon to collect
|
||||||
|
// further points
|
||||||
|
const std::ptrdiff_t nIdxNewPolygon=rPolygonPool.alloc();
|
||||||
|
rPolygonPool.get(nIdxNewPolygon).setPolygonPoolIndex(nIdxNewPolygon);
|
||||||
|
rPolygonPool.get(nIdxNewPolygon).append(rIntersectionPoint);
|
||||||
|
|
||||||
|
rActiveEdge.setTargetPolygonIndex(nIdxNewPolygon);
|
||||||
|
|
||||||
|
return nIdxNewPolygon;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const std::ptrdiff_t nTmpIdx=rActiveEdge.getTargetPolygonIndex();
|
||||||
|
ImplPolygon& rTmp=rPolygonPool.get(nTmpIdx);
|
||||||
|
|
||||||
|
// active edge's polygon has points
|
||||||
|
// already. ours need to go in front of them.
|
||||||
|
maPoints.insert(maPoints.end(),
|
||||||
|
rTmp.maPoints.begin(),
|
||||||
|
rTmp.maPoints.end());
|
||||||
|
|
||||||
|
rTmp.maPoints.clear();
|
||||||
|
rTmp.append(rIntersectionPoint);
|
||||||
|
|
||||||
|
// adjust leading edges, we're switching the polygon
|
||||||
|
ActiveEdge* const pFarEdge=rTmp.mpLeadingRightEdge;
|
||||||
|
ActiveEdge* const pNearEdge=&rActiveEdge;
|
||||||
|
|
||||||
|
rTmp.mpLeadingRightEdge = NULL;
|
||||||
|
pNearEdge->setTargetPolygonIndex(nTmpIdx);
|
||||||
|
|
||||||
|
mpLeadingRightEdge = pFarEdge;
|
||||||
|
pFarEdge->setTargetPolygonIndex(mnIdx);
|
||||||
|
|
||||||
|
return nTmpIdx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ptrdiff_t handleComplexRightEdge(ActiveEdge& rActiveEdge,
|
||||||
|
const B2DPoint& rIntersectionPoint,
|
||||||
|
VectorOfPolygons& rPolygonPool)
|
||||||
|
{
|
||||||
|
const std::ptrdiff_t nTmpIdx=rActiveEdge.getTargetPolygonIndex();
|
||||||
|
ImplPolygon& rTmp=rPolygonPool.get(nTmpIdx);
|
||||||
|
|
||||||
|
rTmp.append(rIntersectionPoint);
|
||||||
|
|
||||||
|
rActiveEdge.setTargetPolygonIndex(mnIdx);
|
||||||
|
mpLeadingRightEdge = &rActiveEdge;
|
||||||
|
|
||||||
|
rTmp.mpLeadingRightEdge = NULL;
|
||||||
|
|
||||||
|
return nTmpIdx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// True when sweep line hits our own active edge
|
||||||
|
bool metOwnEdge(const SweepLineEvent& rEvent,
|
||||||
|
ActiveEdge& rActiveEdge)
|
||||||
|
{
|
||||||
|
const bool bHitOwnEdge=&rEvent.getRect() == &rActiveEdge.getRect();
|
||||||
|
return bHitOwnEdge;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieve B2DPolygon from this object
|
||||||
|
B2DPolygon getPolygon() const
|
||||||
|
{
|
||||||
|
B2DPolygon aRes;
|
||||||
|
std::for_each( maPoints.begin(),
|
||||||
|
maPoints.end(),
|
||||||
|
boost::bind(
|
||||||
|
&B2DPolygon::append,
|
||||||
|
boost::ref(aRes),
|
||||||
|
_1,
|
||||||
|
1 ) );
|
||||||
|
aRes.setClosed( true );
|
||||||
|
return aRes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Finish this polygon, push to result set.
|
||||||
|
*/
|
||||||
|
void finish(B2DPolyPolygon& rRes)
|
||||||
|
{
|
||||||
|
OSL_PRECOND( maPoints.empty() ||
|
||||||
|
maPoints.front().getX() == maPoints.back().getX() ||
|
||||||
|
maPoints.front().getY() == maPoints.back().getY(),
|
||||||
|
"ImplPolygon::finish(): first and last point violate 90 degree line angle constraint!" );
|
||||||
|
|
||||||
|
mbIsFinished = true;
|
||||||
|
mpLeadingRightEdge = NULL;
|
||||||
|
|
||||||
|
rRes.append(getPolygon());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Refers to the current leading edge element of this
|
||||||
|
polygon, or NULL. The leading edge denotes the 'front'
|
||||||
|
of the polygon vertex sequence, i.e. the coordinates
|
||||||
|
at the polygon's leading edge are returned from
|
||||||
|
maPoints.front()
|
||||||
|
*/
|
||||||
|
ActiveEdge* mpLeadingRightEdge;
|
||||||
|
|
||||||
|
/// current index into vector pool
|
||||||
|
std::ptrdiff_t mnIdx;
|
||||||
|
|
||||||
|
/// Container for the actual polygon points
|
||||||
|
std::vector<B2DPoint> maPoints;
|
||||||
|
|
||||||
|
/// When true, this polygon is 'done', i.e. nothing must be added anymore.
|
||||||
|
bool mbIsFinished;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Init sweep line event list
|
||||||
|
|
||||||
|
This method fills the event list with the sweep line
|
||||||
|
events generated from the input rectangles, and sorts them
|
||||||
|
with increasing x.
|
||||||
|
*/
|
||||||
|
void setupSweepLineEventListFromRanges( VectorOfEvents& o_rEventVector,
|
||||||
|
const std::vector<B2DRange>& rRanges,
|
||||||
|
const std::vector<B2VectorOrientation>& rOrientations )
|
||||||
|
{
|
||||||
|
// we need exactly 2*rectVec.size() events: one for the
|
||||||
|
// left, and one for the right edge of each rectangle
|
||||||
|
o_rEventVector.clear();
|
||||||
|
o_rEventVector.reserve( 2*rRanges.size() );
|
||||||
|
|
||||||
|
// generate events
|
||||||
|
// ===============
|
||||||
|
|
||||||
|
// first pass: add all left edges in increasing order
|
||||||
|
std::vector<B2DRange>::const_iterator aCurrRect=rRanges.begin();
|
||||||
|
std::vector<B2VectorOrientation>::const_iterator aCurrOrientation=rOrientations.begin();
|
||||||
|
const std::vector<B2DRange>::const_iterator aEnd=rRanges.end();
|
||||||
|
const std::vector<B2VectorOrientation>::const_iterator aEndOrientation=rOrientations.end();
|
||||||
|
while( aCurrRect != aEnd && aCurrOrientation != aEndOrientation )
|
||||||
|
{
|
||||||
|
const B2DRectangle& rCurrRect( *aCurrRect++ );
|
||||||
|
|
||||||
|
o_rEventVector.push_back(
|
||||||
|
SweepLineEvent( rCurrRect.getMinX(),
|
||||||
|
rCurrRect,
|
||||||
|
SweepLineEvent::STARTING_EDGE,
|
||||||
|
(*aCurrOrientation++) == ORIENTATION_POSITIVE ?
|
||||||
|
SweepLineEvent::PROCEED_UP : SweepLineEvent::PROCEED_DOWN) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// second pass: add all right edges in reversed order
|
||||||
|
std::vector<B2DRange>::const_reverse_iterator aCurrRectR=rRanges.rbegin();
|
||||||
|
std::vector<B2VectorOrientation>::const_reverse_iterator aCurrOrientationR=rOrientations.rbegin();
|
||||||
|
const std::vector<B2DRange>::const_reverse_iterator aEndR=rRanges.rend();
|
||||||
|
const std::vector<B2VectorOrientation>::const_reverse_iterator aEndOrientationR=rOrientations.rend();
|
||||||
|
while( aCurrRectR != aEndR )
|
||||||
|
{
|
||||||
|
const B2DRectangle& rCurrRect( *aCurrRectR++ );
|
||||||
|
|
||||||
|
o_rEventVector.push_back(
|
||||||
|
SweepLineEvent( rCurrRect.getMaxX(),
|
||||||
|
rCurrRect,
|
||||||
|
SweepLineEvent::FINISHING_EDGE,
|
||||||
|
(*aCurrOrientationR++) == ORIENTATION_POSITIVE ?
|
||||||
|
SweepLineEvent::PROCEED_DOWN : SweepLineEvent::PROCEED_UP ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort events
|
||||||
|
// ===========
|
||||||
|
|
||||||
|
// since we use stable_sort, the order of events with the
|
||||||
|
// same x value will not change. The elaborate two-pass
|
||||||
|
// add above thus ensures, that for each two rectangles
|
||||||
|
// with similar left and right x coordinates, the
|
||||||
|
// rectangle whose left event comes first will have its
|
||||||
|
// right event come last. This is advantageous for the
|
||||||
|
// clip algorithm below, see handleRightEdgeCrossing().
|
||||||
|
|
||||||
|
// TODO(P3): Use radix sort (from
|
||||||
|
// b2dpolypolygonrasterconverter, or have your own
|
||||||
|
// templatized version).
|
||||||
|
std::stable_sort( o_rEventVector.begin(),
|
||||||
|
o_rEventVector.end() );
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Insert two active edge segments for the given rectangle.
|
||||||
|
|
||||||
|
This method creates two active edge segments from the
|
||||||
|
given rect, and inserts them into the active edge list,
|
||||||
|
such that this stays sorted (if it was before).
|
||||||
|
|
||||||
|
@param io_rEdgeList
|
||||||
|
Active edge list to insert into
|
||||||
|
|
||||||
|
@param io_rPolygons
|
||||||
|
Vector of polygons. Each rectangle added creates one
|
||||||
|
tentative result polygon in this vector, and the edge list
|
||||||
|
entries holds a reference to that polygon (this _requires_
|
||||||
|
that the polygon vector does not reallocate, i.e. it must
|
||||||
|
have at least the maximal number of rectangles reserved)
|
||||||
|
|
||||||
|
@param o_CurrentPolygon
|
||||||
|
The then-current polygon when processing this sweep line
|
||||||
|
event
|
||||||
|
|
||||||
|
@param rCurrEvent
|
||||||
|
The actual event that caused this call
|
||||||
|
*/
|
||||||
|
void createActiveEdgesFromStartEvent( ListOfEdges& io_rEdgeList,
|
||||||
|
VectorOfPolygons& io_rPolygonPool,
|
||||||
|
SweepLineEvent& rCurrEvent )
|
||||||
|
{
|
||||||
|
ListOfEdges aNewEdges;
|
||||||
|
const B2DRectangle& rRect=rCurrEvent.getRect();
|
||||||
|
const bool bGoesDown=rCurrEvent.getEdgeDirection() == SweepLineEvent::PROCEED_DOWN;
|
||||||
|
|
||||||
|
// start event - new rect starts here, needs polygon to
|
||||||
|
// collect points into
|
||||||
|
const std::ptrdiff_t nIdxPolygon=io_rPolygonPool.alloc();
|
||||||
|
io_rPolygonPool.get(nIdxPolygon).setPolygonPoolIndex(nIdxPolygon);
|
||||||
|
|
||||||
|
// upper edge
|
||||||
|
aNewEdges.push_back(
|
||||||
|
ActiveEdge(
|
||||||
|
rRect,
|
||||||
|
rRect.getMinY(),
|
||||||
|
bGoesDown ? nIdxPolygon : -1,
|
||||||
|
ActiveEdge::UPPER,
|
||||||
|
bGoesDown ? ActiveEdge::PROCEED_LEFT : ActiveEdge::PROCEED_RIGHT) );
|
||||||
|
// lower edge
|
||||||
|
aNewEdges.push_back(
|
||||||
|
ActiveEdge(
|
||||||
|
rRect,
|
||||||
|
rRect.getMaxY(),
|
||||||
|
bGoesDown ? -1 : nIdxPolygon,
|
||||||
|
ActiveEdge::LOWER,
|
||||||
|
bGoesDown ? ActiveEdge::PROCEED_RIGHT : ActiveEdge::PROCEED_LEFT ) );
|
||||||
|
|
||||||
|
// furthermore, have to respect a special tie-breaking
|
||||||
|
// rule here, for edges which share the same y value:
|
||||||
|
// newly added upper edges must be inserted _before_ any
|
||||||
|
// other edge with the same y value, and newly added lower
|
||||||
|
// edges must be _after_ all other edges with the same
|
||||||
|
// y. This ensures that the left vertical edge processing
|
||||||
|
// below encounters the upper edge of the current rect
|
||||||
|
// first, and the lower edge last, which automatically
|
||||||
|
// starts and finishes this rect correctly (as only then,
|
||||||
|
// the polygon will have their associated active edges
|
||||||
|
// set).
|
||||||
|
const double nMinY( rRect.getMinY() );
|
||||||
|
const double nMaxY( rRect.getMaxY() );
|
||||||
|
ListOfEdges::iterator aCurr( io_rEdgeList.begin() );
|
||||||
|
const ListOfEdges::iterator aEnd ( io_rEdgeList.end() );
|
||||||
|
while( aCurr != aEnd )
|
||||||
|
{
|
||||||
|
const double nCurrY( aCurr->getInvariantCoord() );
|
||||||
|
|
||||||
|
if( nCurrY >= nMinY &&
|
||||||
|
aNewEdges.size() == 2 ) // only add, if not yet done.
|
||||||
|
{
|
||||||
|
// insert upper edge _before_ aCurr. Thus, it will
|
||||||
|
// be the first entry for a range of equal y
|
||||||
|
// values. Using splice here, since we hold
|
||||||
|
// references to the moved list element!
|
||||||
|
io_rEdgeList.splice( aCurr,
|
||||||
|
aNewEdges,
|
||||||
|
aNewEdges.begin() );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( nCurrY > nMaxY )
|
||||||
|
{
|
||||||
|
// insert lower edge _before_ aCurr. Thus, it will
|
||||||
|
// be the last entry for a range of equal y values
|
||||||
|
// (aCurr is the first entry strictly larger than
|
||||||
|
// nMaxY). Using splice here, since we hold
|
||||||
|
// references to the moved list element!
|
||||||
|
io_rEdgeList.splice( aCurr,
|
||||||
|
aNewEdges,
|
||||||
|
aNewEdges.begin() );
|
||||||
|
// done with insertion, can early-exit here.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
++aCurr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// append remainder of aNewList (might still contain 2 or
|
||||||
|
// 1 elements, depending of the contents of io_rEdgeList).
|
||||||
|
io_rEdgeList.splice( aCurr,
|
||||||
|
aNewEdges );
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool isSameRect(ActiveEdge& rEdge,
|
||||||
|
const basegfx::B2DRange& rRect)
|
||||||
|
{
|
||||||
|
return &rEdge.getRect() == &rRect;
|
||||||
|
}
|
||||||
|
|
||||||
|
// wow what a hack. necessary because stl's list::erase does
|
||||||
|
// not eat reverse_iterator
|
||||||
|
template<typename Cont, typename Iter> Iter eraseFromList(Cont&, Iter);
|
||||||
|
template<> inline ListOfEdges::iterator eraseFromList(
|
||||||
|
ListOfEdges& rList, ListOfEdges::iterator aIter)
|
||||||
|
{
|
||||||
|
return rList.erase(aIter);
|
||||||
|
}
|
||||||
|
template<> inline ListOfEdges::reverse_iterator eraseFromList(
|
||||||
|
ListOfEdges& rList, ListOfEdges::reverse_iterator aIter)
|
||||||
|
{
|
||||||
|
return ListOfEdges::reverse_iterator(
|
||||||
|
rList.erase(boost::prior(aIter.base())));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<int bPerformErase,
|
||||||
|
typename Iterator> inline void processActiveEdges(
|
||||||
|
Iterator first,
|
||||||
|
Iterator last,
|
||||||
|
ListOfEdges& rActiveEdgeList,
|
||||||
|
SweepLineEvent& rCurrEvent,
|
||||||
|
VectorOfPolygons& rPolygonPool,
|
||||||
|
B2DPolyPolygon& rRes )
|
||||||
|
{
|
||||||
|
const basegfx::B2DRange& rCurrRect=rCurrEvent.getRect();
|
||||||
|
|
||||||
|
// fast-forward to rCurrEvent's first active edge (holds
|
||||||
|
// for both starting and finishing sweep line events, a
|
||||||
|
// rect is regarded _outside_ any rects whose events have
|
||||||
|
// started earlier
|
||||||
|
first = std::find_if(first, last,
|
||||||
|
boost::bind(
|
||||||
|
&isSameRect,
|
||||||
|
_1,
|
||||||
|
boost::cref(rCurrRect)));
|
||||||
|
|
||||||
|
if(first == last)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int nCount=0;
|
||||||
|
std::ptrdiff_t nCurrPolyIdx=-1;
|
||||||
|
while(first != last)
|
||||||
|
{
|
||||||
|
if( nCurrPolyIdx == -1 )
|
||||||
|
nCurrPolyIdx=first->getTargetPolygonIndex();
|
||||||
|
|
||||||
|
OSL_ASSERT(nCurrPolyIdx != -1);
|
||||||
|
|
||||||
|
// second encounter of my rect -> second edge
|
||||||
|
// encountered, done
|
||||||
|
const bool bExit=
|
||||||
|
nCount &&
|
||||||
|
isSameRect(*first,
|
||||||
|
rCurrRect);
|
||||||
|
|
||||||
|
// deal with current active edge
|
||||||
|
nCurrPolyIdx =
|
||||||
|
rPolygonPool.get(nCurrPolyIdx).intersect(
|
||||||
|
rCurrEvent,
|
||||||
|
*first,
|
||||||
|
rPolygonPool,
|
||||||
|
rRes,
|
||||||
|
bExit);
|
||||||
|
|
||||||
|
// prune upper & lower active edges, if requested
|
||||||
|
if( bPerformErase && (bExit || !nCount) )
|
||||||
|
first = eraseFromList(rActiveEdgeList,first);
|
||||||
|
else
|
||||||
|
++first;
|
||||||
|
|
||||||
|
// delayed exit, had to prune first
|
||||||
|
if( bExit )
|
||||||
|
return;
|
||||||
|
|
||||||
|
++nCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<int bPerformErase> inline void processActiveEdgesTopDown(
|
||||||
|
SweepLineEvent& rCurrEvent,
|
||||||
|
ListOfEdges& rActiveEdgeList,
|
||||||
|
VectorOfPolygons& rPolygonPool,
|
||||||
|
B2DPolyPolygon& rRes )
|
||||||
|
{
|
||||||
|
processActiveEdges<bPerformErase>(
|
||||||
|
rActiveEdgeList. begin(),
|
||||||
|
rActiveEdgeList. end(),
|
||||||
|
rActiveEdgeList,
|
||||||
|
rCurrEvent,
|
||||||
|
rPolygonPool,
|
||||||
|
rRes);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<int bPerformErase> inline void processActiveEdgesBottomUp(
|
||||||
|
SweepLineEvent& rCurrEvent,
|
||||||
|
ListOfEdges& rActiveEdgeList,
|
||||||
|
VectorOfPolygons& rPolygonPool,
|
||||||
|
B2DPolyPolygon& rRes )
|
||||||
|
{
|
||||||
|
processActiveEdges<bPerformErase>(
|
||||||
|
rActiveEdgeList. rbegin(),
|
||||||
|
rActiveEdgeList. rend(),
|
||||||
|
rActiveEdgeList,
|
||||||
|
rCurrEvent,
|
||||||
|
rPolygonPool,
|
||||||
|
rRes);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum{ NoErase=0, PerformErase=1 };
|
||||||
|
|
||||||
|
void handleStartingEdge( SweepLineEvent& rCurrEvent,
|
||||||
|
ListOfEdges& rActiveEdgeList,
|
||||||
|
VectorOfPolygons& rPolygonPool,
|
||||||
|
B2DPolyPolygon& rRes)
|
||||||
|
{
|
||||||
|
// inject two new active edges for rect
|
||||||
|
createActiveEdgesFromStartEvent( rActiveEdgeList,
|
||||||
|
rPolygonPool,
|
||||||
|
rCurrEvent );
|
||||||
|
|
||||||
|
if( SweepLineEvent::PROCEED_DOWN == rCurrEvent.getEdgeDirection() )
|
||||||
|
processActiveEdgesTopDown<NoErase>(
|
||||||
|
rCurrEvent, rActiveEdgeList, rPolygonPool, rRes);
|
||||||
|
else
|
||||||
|
processActiveEdgesBottomUp<NoErase>(
|
||||||
|
rCurrEvent, rActiveEdgeList, rPolygonPool, rRes);
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleFinishingEdge( SweepLineEvent& rCurrEvent,
|
||||||
|
ListOfEdges& rActiveEdgeList,
|
||||||
|
VectorOfPolygons& rPolygonPool,
|
||||||
|
B2DPolyPolygon& rRes)
|
||||||
|
{
|
||||||
|
if( SweepLineEvent::PROCEED_DOWN == rCurrEvent.getEdgeDirection() )
|
||||||
|
processActiveEdgesTopDown<PerformErase>(
|
||||||
|
rCurrEvent, rActiveEdgeList, rPolygonPool, rRes);
|
||||||
|
else
|
||||||
|
processActiveEdgesBottomUp<PerformErase>(
|
||||||
|
rCurrEvent, rActiveEdgeList, rPolygonPool, rRes);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void handleSweepLineEvent( SweepLineEvent& rCurrEvent,
|
||||||
|
ListOfEdges& rActiveEdgeList,
|
||||||
|
VectorOfPolygons& rPolygonPool,
|
||||||
|
B2DPolyPolygon& rRes)
|
||||||
|
{
|
||||||
|
if( SweepLineEvent::STARTING_EDGE == rCurrEvent.getEdgeType() )
|
||||||
|
handleStartingEdge(rCurrEvent,rActiveEdgeList,rPolygonPool,rRes);
|
||||||
|
else
|
||||||
|
handleFinishingEdge(rCurrEvent,rActiveEdgeList,rPolygonPool,rRes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace tools
|
||||||
|
{
|
||||||
|
B2DPolyPolygon solveCrossovers(const std::vector<B2DRange>& rRanges,
|
||||||
|
const std::vector<B2VectorOrientation>& rOrientations)
|
||||||
|
{
|
||||||
|
// sweep-line algorithm to generate a poly-polygon
|
||||||
|
// from a bunch of rectangles
|
||||||
|
// ===============================================
|
||||||
|
//
|
||||||
|
// This algorithm uses the well-known sweep line
|
||||||
|
// concept, explained in every good text book about
|
||||||
|
// computational geometry.
|
||||||
|
//
|
||||||
|
// We start with creating two structures for every
|
||||||
|
// rectangle, one representing the left x coordinate,
|
||||||
|
// one representing the right x coordinate (and both
|
||||||
|
// referencing the original rect). These structs are
|
||||||
|
// sorted with increasing x coordinates.
|
||||||
|
//
|
||||||
|
// Then, we start processing the resulting list from
|
||||||
|
// the beginning. Every entry in the list defines a
|
||||||
|
// point in time of the line sweeping from left to
|
||||||
|
// right across all rectangles.
|
||||||
|
VectorOfEvents aSweepLineEvents;
|
||||||
|
setupSweepLineEventListFromRanges( aSweepLineEvents,
|
||||||
|
rRanges,
|
||||||
|
rOrientations );
|
||||||
|
|
||||||
|
B2DPolyPolygon aRes;
|
||||||
|
VectorOfPolygons aPolygonPool;
|
||||||
|
ListOfEdges aActiveEdgeList;
|
||||||
|
|
||||||
|
// sometimes not enough, but a usable compromise
|
||||||
|
aPolygonPool.reserve( rRanges.size() );
|
||||||
|
|
||||||
|
std::for_each( aSweepLineEvents.begin(),
|
||||||
|
aSweepLineEvents.end(),
|
||||||
|
boost::bind(
|
||||||
|
&handleSweepLineEvent,
|
||||||
|
_1,
|
||||||
|
boost::ref(aActiveEdgeList),
|
||||||
|
boost::ref(aPolygonPool),
|
||||||
|
boost::ref(aRes)) );
|
||||||
|
|
||||||
|
return aRes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@@ -47,7 +47,8 @@ SLOFILES= \
|
|||||||
$(SLO)$/b1drange.obj \
|
$(SLO)$/b1drange.obj \
|
||||||
$(SLO)$/b2drange.obj \
|
$(SLO)$/b2drange.obj \
|
||||||
$(SLO)$/b2xrange.obj \
|
$(SLO)$/b2xrange.obj \
|
||||||
$(SLO)$/b2dmultirange.obj \
|
$(SLO)$/b2dpolyrange.obj \
|
||||||
|
$(SLO)$/b2drangeclipper.obj \
|
||||||
$(SLO)$/b3drange.obj
|
$(SLO)$/b3drange.obj
|
||||||
|
|
||||||
# --- Targets ----------------------------------
|
# --- Targets ----------------------------------
|
||||||
|
@@ -41,7 +41,9 @@
|
|||||||
#include <basegfx/curve/b2dcubicbezier.hxx>
|
#include <basegfx/curve/b2dcubicbezier.hxx>
|
||||||
#include <basegfx/curve/b2dbeziertools.hxx>
|
#include <basegfx/curve/b2dbeziertools.hxx>
|
||||||
#include <basegfx/polygon/b2dpolypolygontools.hxx>
|
#include <basegfx/polygon/b2dpolypolygontools.hxx>
|
||||||
#include <basegfx/range/b2dmultirange.hxx>
|
#include <basegfx/polygon/b2dpolygonclipper.hxx>
|
||||||
|
#include <basegfx/polygon/b2dpolypolygon.hxx>
|
||||||
|
#include <basegfx/range/b2dpolyrange.hxx>
|
||||||
#include <basegfx/numeric/ftools.hxx>
|
#include <basegfx/numeric/ftools.hxx>
|
||||||
#include <basegfx/color/bcolor.hxx>
|
#include <basegfx/color/bcolor.hxx>
|
||||||
#include <basegfx/color/bcolortools.hxx>
|
#include <basegfx/color/bcolortools.hxx>
|
||||||
@@ -56,214 +58,6 @@ using namespace ::basegfx;
|
|||||||
|
|
||||||
namespace basegfx2d
|
namespace basegfx2d
|
||||||
{
|
{
|
||||||
/// Gets a random ordinal [0,n)
|
|
||||||
inline double getRandomOrdinal( const ::std::size_t n )
|
|
||||||
{
|
|
||||||
return double(n) * rand() / (RAND_MAX + 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
class b2dmultirange : public CppUnit::TestFixture
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
B2DMultiRange aDisjunctRanges;
|
|
||||||
B2DMultiRange aEqualRanges;
|
|
||||||
B2DMultiRange aIntersectionN;
|
|
||||||
B2DMultiRange aIntersectionE;
|
|
||||||
B2DMultiRange aIntersectionS;
|
|
||||||
B2DMultiRange aIntersectionW;
|
|
||||||
B2DMultiRange aIntersectionNE;
|
|
||||||
B2DMultiRange aIntersectionSE;
|
|
||||||
B2DMultiRange aIntersectionSW;
|
|
||||||
B2DMultiRange aIntersectionNW;
|
|
||||||
B2DMultiRange aRingIntersection;
|
|
||||||
B2DMultiRange aComplexIntersections;
|
|
||||||
B2DMultiRange aRandomIntersections;
|
|
||||||
|
|
||||||
public:
|
|
||||||
// initialise your test code values here.
|
|
||||||
void setUp()
|
|
||||||
{
|
|
||||||
B2DRange aCenter(1.0, 1.0, -1.0, -1.0);
|
|
||||||
B2DRange aOffside(9.0, 9.0, 11.0, 11.0);
|
|
||||||
B2DRange aNorth(1.0, 0.0, -1.0, -2.0);
|
|
||||||
B2DRange aSouth(1.0, 2.0, -1.0, 0.0);
|
|
||||||
B2DRange aEast(0.0, 1.0, 2.0, -1.0);
|
|
||||||
B2DRange aWest(-2.0, 1.0, 0.0, -1.0);
|
|
||||||
B2DRange aNorthEast(0.0, 0.0, 2.0, -2.0);
|
|
||||||
B2DRange aSouthEast(0.0, 0.0, 2.0, 2.0);
|
|
||||||
B2DRange aSouthWest(0.0, 0.0, -2.0, 2.0);
|
|
||||||
B2DRange aNorthWest(0.0, 0.0, -2.0, -2.0);
|
|
||||||
|
|
||||||
B2DRange aNorth2(-1.5, 0.5, 1.5, 3.5);
|
|
||||||
B2DRange aSouth2(-1.5, -0.5, 1.5, -3.5);
|
|
||||||
B2DRange aEast2 (0.5, -1.5, 3.5, 1.5);
|
|
||||||
B2DRange aWest2 (-0.5, -1.5,-3.5, 1.5);
|
|
||||||
|
|
||||||
::std::ofstream output("multirange_testcases.gnuplot");
|
|
||||||
DebugPlotter aPlotter( "multirange testcases",
|
|
||||||
output );
|
|
||||||
|
|
||||||
aPlotter.plot( aCenter, "center" );
|
|
||||||
aPlotter.plot( aOffside, "offside" );
|
|
||||||
aPlotter.plot( aNorth, "north" );
|
|
||||||
aPlotter.plot( aSouth, "south" );
|
|
||||||
aPlotter.plot( aEast, "east" );
|
|
||||||
aPlotter.plot( aWest, "west" );
|
|
||||||
aPlotter.plot( aNorthEast, "northeast" );
|
|
||||||
aPlotter.plot( aSouthEast, "southeast" );
|
|
||||||
aPlotter.plot( aSouthWest, "southwest" );
|
|
||||||
aPlotter.plot( aNorthWest, "northwest" );
|
|
||||||
|
|
||||||
aDisjunctRanges.addRange( aCenter );
|
|
||||||
aDisjunctRanges.addRange( aOffside );
|
|
||||||
|
|
||||||
aEqualRanges.addRange( aCenter );
|
|
||||||
aEqualRanges.addRange( aCenter );
|
|
||||||
|
|
||||||
aIntersectionN.addRange( aCenter );
|
|
||||||
aIntersectionN.addRange( aNorth );
|
|
||||||
|
|
||||||
aIntersectionE.addRange( aCenter );
|
|
||||||
aIntersectionE.addRange( aEast );
|
|
||||||
|
|
||||||
aIntersectionS.addRange( aCenter );
|
|
||||||
aIntersectionS.addRange( aSouth );
|
|
||||||
|
|
||||||
aIntersectionW.addRange( aCenter );
|
|
||||||
aIntersectionW.addRange( aWest );
|
|
||||||
|
|
||||||
aIntersectionNE.addRange( aCenter );
|
|
||||||
aIntersectionNE.addRange( aNorthEast );
|
|
||||||
|
|
||||||
aIntersectionSE.addRange( aCenter );
|
|
||||||
aIntersectionSE.addRange( aSouthEast );
|
|
||||||
|
|
||||||
aIntersectionSW.addRange( aCenter );
|
|
||||||
aIntersectionSW.addRange( aSouthWest );
|
|
||||||
|
|
||||||
aIntersectionNW.addRange( aCenter );
|
|
||||||
aIntersectionNW.addRange( aNorthWest );
|
|
||||||
|
|
||||||
aRingIntersection.addRange( aNorth2 );
|
|
||||||
aRingIntersection.addRange( aEast2 );
|
|
||||||
aRingIntersection.addRange( aSouth2 );
|
|
||||||
aRingIntersection.addRange( aWest2 );
|
|
||||||
|
|
||||||
aComplexIntersections.addRange( aCenter );
|
|
||||||
aComplexIntersections.addRange( aOffside );
|
|
||||||
aComplexIntersections.addRange( aCenter );
|
|
||||||
aComplexIntersections.addRange( aNorth );
|
|
||||||
aComplexIntersections.addRange( aEast );
|
|
||||||
aComplexIntersections.addRange( aSouth );
|
|
||||||
aComplexIntersections.addRange( aWest );
|
|
||||||
aComplexIntersections.addRange( aNorthEast );
|
|
||||||
aComplexIntersections.addRange( aSouthEast );
|
|
||||||
aComplexIntersections.addRange( aSouthWest );
|
|
||||||
aComplexIntersections.addRange( aNorthWest );
|
|
||||||
|
|
||||||
/*
|
|
||||||
for( int i=0; i<10; ++i )
|
|
||||||
{
|
|
||||||
B2DRange aRandomRange(
|
|
||||||
getRandomOrdinal( 10 ),
|
|
||||||
getRandomOrdinal( 10 ),
|
|
||||||
getRandomOrdinal( 10 ),
|
|
||||||
getRandomOrdinal( 10 ) );
|
|
||||||
|
|
||||||
aRandomIntersections.addRange( aRandomRange );
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
void tearDown()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
::basegfx::B2DPolyPolygon shiftPoly( int nCount,
|
|
||||||
const ::basegfx::B2DPolyPolygon& rPoly )
|
|
||||||
{
|
|
||||||
B2DHomMatrix aMatrix;
|
|
||||||
aMatrix.translate( nCount*4.0,
|
|
||||||
10.0-nCount*2.0 );
|
|
||||||
|
|
||||||
::basegfx::B2DPolyPolygon aRes( rPoly );
|
|
||||||
aRes.transform( aMatrix );
|
|
||||||
|
|
||||||
return aRes;
|
|
||||||
}
|
|
||||||
|
|
||||||
void getPolyPolygon()
|
|
||||||
{
|
|
||||||
::std::ofstream output("multirange_getpolypolygon.gnuplot");
|
|
||||||
DebugPlotter aPlotter( "multirange getPolyPolygon",
|
|
||||||
output );
|
|
||||||
|
|
||||||
B2DPolyPolygon result;
|
|
||||||
|
|
||||||
aPlotter.plot( shiftPoly(
|
|
||||||
0,
|
|
||||||
aDisjunctRanges.getPolyPolygon() ),
|
|
||||||
"disjunct" );
|
|
||||||
aPlotter.plot( shiftPoly(
|
|
||||||
1,
|
|
||||||
aEqualRanges.getPolyPolygon() ),
|
|
||||||
"equal" );
|
|
||||||
aPlotter.plot( shiftPoly(
|
|
||||||
2,
|
|
||||||
aIntersectionN.getPolyPolygon() ),
|
|
||||||
"intersectionN" );
|
|
||||||
aPlotter.plot( shiftPoly(
|
|
||||||
3,
|
|
||||||
aIntersectionE.getPolyPolygon() ),
|
|
||||||
"intersectionE" );
|
|
||||||
aPlotter.plot( shiftPoly(
|
|
||||||
4,
|
|
||||||
aIntersectionS.getPolyPolygon() ),
|
|
||||||
"intersectionS" );
|
|
||||||
aPlotter.plot( shiftPoly(
|
|
||||||
5,
|
|
||||||
aIntersectionW.getPolyPolygon() ),
|
|
||||||
"intersectionW" );
|
|
||||||
aPlotter.plot( shiftPoly(
|
|
||||||
6,
|
|
||||||
aIntersectionNE.getPolyPolygon() ),
|
|
||||||
"intersectionNE" );
|
|
||||||
aPlotter.plot( shiftPoly(
|
|
||||||
7,
|
|
||||||
aIntersectionSE.getPolyPolygon() ),
|
|
||||||
"intersectionSE" );
|
|
||||||
aPlotter.plot( shiftPoly(
|
|
||||||
8,
|
|
||||||
aIntersectionSW.getPolyPolygon() ),
|
|
||||||
"intersectionSW" );
|
|
||||||
aPlotter.plot( shiftPoly(
|
|
||||||
9,
|
|
||||||
aIntersectionNW.getPolyPolygon() ),
|
|
||||||
"intersectionNW" );
|
|
||||||
aPlotter.plot( shiftPoly(
|
|
||||||
10,
|
|
||||||
aRingIntersection.getPolyPolygon() ),
|
|
||||||
"intersection ring" );
|
|
||||||
aPlotter.plot( shiftPoly(
|
|
||||||
11,
|
|
||||||
aComplexIntersections.getPolyPolygon() ),
|
|
||||||
"intersection complex" );
|
|
||||||
aPlotter.plot( shiftPoly(
|
|
||||||
12,
|
|
||||||
aRandomIntersections.getPolyPolygon() ),
|
|
||||||
"intersection random" );
|
|
||||||
|
|
||||||
CPPUNIT_ASSERT_MESSAGE("getPolyPolygon", true );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Change the following lines only, if you add, remove or rename
|
|
||||||
// member functions of the current class,
|
|
||||||
// because these macros are need by auto register mechanism.
|
|
||||||
|
|
||||||
CPPUNIT_TEST_SUITE(b2dmultirange);
|
|
||||||
CPPUNIT_TEST(getPolyPolygon);
|
|
||||||
CPPUNIT_TEST_SUITE_END();
|
|
||||||
}; // class b2dmultirange
|
|
||||||
|
|
||||||
class b2dsvgdimpex : public CppUnit::TestFixture
|
class b2dsvgdimpex : public CppUnit::TestFixture
|
||||||
{
|
{
|
||||||
@@ -505,6 +299,39 @@ public:
|
|||||||
CPPUNIT_TEST_SUITE_END();
|
CPPUNIT_TEST_SUITE_END();
|
||||||
}; // class b2dsvgdimpex
|
}; // class b2dsvgdimpex
|
||||||
|
|
||||||
|
class b2dpolyrange : public CppUnit::TestFixture
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
public:
|
||||||
|
void setUp()
|
||||||
|
{}
|
||||||
|
|
||||||
|
void tearDown()
|
||||||
|
{}
|
||||||
|
|
||||||
|
void check()
|
||||||
|
{
|
||||||
|
B2DPolyRange aRange;
|
||||||
|
aRange.appendElement(B2DRange(0,0,1,1),ORIENTATION_POSITIVE);
|
||||||
|
aRange.appendElement(B2DRange(2,2,3,3),ORIENTATION_POSITIVE);
|
||||||
|
|
||||||
|
CPPUNIT_ASSERT_MESSAGE("simple poly range - count",
|
||||||
|
aRange.count() == 2);
|
||||||
|
CPPUNIT_ASSERT_MESSAGE("simple poly range - first element",
|
||||||
|
aRange.getElement(0).head == B2DRange(0,0,1,1));
|
||||||
|
CPPUNIT_ASSERT_MESSAGE("simple poly range - second element",
|
||||||
|
aRange.getElement(1).head == B2DRange(2,2,3,3));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Change the following lines only, if you add, remove or rename
|
||||||
|
// member functions of the current class,
|
||||||
|
// because these macros are need by auto register mechanism.
|
||||||
|
|
||||||
|
CPPUNIT_TEST_SUITE(b2dpolyrange);
|
||||||
|
CPPUNIT_TEST(check);
|
||||||
|
CPPUNIT_TEST_SUITE_END();
|
||||||
|
};
|
||||||
|
|
||||||
class b2dbeziertools : public CppUnit::TestFixture
|
class b2dbeziertools : public CppUnit::TestFixture
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
@@ -1618,8 +1445,9 @@ public:
|
|||||||
}; // class b2dvector
|
}; // class b2dvector
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
//CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(basegfx2d::b2dmultirange, "basegfx2d");
|
|
||||||
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(basegfx2d::b2dsvgdimpex, "basegfx2d");
|
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(basegfx2d::b2dsvgdimpex, "basegfx2d");
|
||||||
|
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(basegfx2d::b2dpolyrange, "basegfx2d");
|
||||||
//CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(basegfx2d::b2dbeziertools, "basegfx2d");
|
//CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(basegfx2d::b2dbeziertools, "basegfx2d");
|
||||||
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(basegfx2d::b2dcubicbezier, "basegfx2d");
|
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(basegfx2d::b2dcubicbezier, "basegfx2d");
|
||||||
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(basegfx2d::b2dhommatrix, "basegfx2d");
|
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(basegfx2d::b2dhommatrix, "basegfx2d");
|
||||||
|
426
basegfx/test/boxclipper.cxx
Normal file
426
basegfx/test/boxclipper.cxx
Normal file
File diff suppressed because one or more lines are too long
@@ -85,6 +85,10 @@ SLOFILES=$(SHL1OBJS)
|
|||||||
.INCLUDE : target.mk
|
.INCLUDE : target.mk
|
||||||
.INCLUDE : _cppunit.mk
|
.INCLUDE : _cppunit.mk
|
||||||
|
|
||||||
|
.IF "$(verbose)"!="" || "$(VERBOSE)"!=""
|
||||||
|
CDEFS+= -DVERBOSE
|
||||||
|
.ENDIF
|
||||||
|
|
||||||
# --- Enable testshl2 execution in normal build ------------------------
|
# --- Enable testshl2 execution in normal build ------------------------
|
||||||
|
|
||||||
$(MISC)$/unittest_succeeded : $(SHL1TARGETN)
|
$(MISC)$/unittest_succeeded : $(SHL1TARGETN)
|
||||||
|
Reference in New Issue
Block a user