#i105939# Adds special box clipping support to basegfx
This commit is contained in:
@@ -83,7 +83,7 @@ namespace basegfx
|
||||
sal_uInt32 count() const;
|
||||
|
||||
/// 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);
|
||||
|
||||
/// Coordinate insert/append
|
||||
@@ -201,7 +201,7 @@ namespace basegfx
|
||||
@return
|
||||
The outer range of the bezier curve/polygon
|
||||
*/
|
||||
B2DRange getB2DRange() const;
|
||||
const B2DRange& getB2DRange() const;
|
||||
|
||||
/** insert other 2D polygons
|
||||
|
||||
@@ -261,6 +261,12 @@ namespace basegfx
|
||||
|
||||
/// apply transformation given in matrix form
|
||||
void transform(const basegfx::B2DHomMatrix& rMatrix);
|
||||
|
||||
// point iterators
|
||||
const B2DPoint* begin() const;
|
||||
const B2DPoint* end() const;
|
||||
B2DPoint* begin();
|
||||
B2DPoint* end();
|
||||
};
|
||||
} // end of namespace basegfx
|
||||
|
||||
|
@@ -128,6 +128,12 @@ namespace basegfx
|
||||
|
||||
// apply transformation given in matrix form to the polygon
|
||||
void transform(const basegfx::B2DHomMatrix& rMatrix);
|
||||
|
||||
// polygon iterators
|
||||
const B2DPolygon* begin() const;
|
||||
const B2DPolygon* end() const;
|
||||
B2DPolygon* begin();
|
||||
B2DPolygon* end();
|
||||
};
|
||||
} // 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:
|
||||
CoordinateData2D()
|
||||
: maPoint()
|
||||
{}
|
||||
CoordinateData2D() {}
|
||||
|
||||
explicit CoordinateData2D(const basegfx::B2DPoint& rData)
|
||||
: maPoint(rData)
|
||||
: B2DPoint(rData)
|
||||
{}
|
||||
|
||||
const basegfx::B2DPoint& getCoordinate() const
|
||||
CoordinateData2D& operator=(const basegfx::B2DPoint& rData)
|
||||
{
|
||||
return maPoint;
|
||||
}
|
||||
|
||||
void setCoordinate(const basegfx::B2DPoint& rValue)
|
||||
{
|
||||
if(rValue != maPoint)
|
||||
maPoint = rValue;
|
||||
}
|
||||
|
||||
bool operator==(const CoordinateData2D& rData ) const
|
||||
{
|
||||
return (maPoint == rData.getCoordinate());
|
||||
B2DPoint::operator=(rData);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void transform(const basegfx::B2DHomMatrix& rMatrix)
|
||||
{
|
||||
maPoint *= rMatrix;
|
||||
*this *= rMatrix;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -115,12 +101,12 @@ public:
|
||||
|
||||
const basegfx::B2DPoint& getCoordinate(sal_uInt32 nIndex) const
|
||||
{
|
||||
return maVector[nIndex].getCoordinate();
|
||||
return maVector[nIndex];
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -221,6 +207,26 @@ public:
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
B2DPoint B2DPolygon::getB2DPoint(sal_uInt32 nIndex) const
|
||||
const B2DPoint& B2DPolygon::getB2DPoint(sal_uInt32 nIndex) const
|
||||
{
|
||||
OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
|
||||
|
||||
@@ -1432,7 +1460,7 @@ namespace basegfx
|
||||
return mpPolygon->getDefaultAdaptiveSubdivision(*this);
|
||||
}
|
||||
|
||||
B2DRange B2DPolygon::getB2DRange() const
|
||||
const B2DRange& B2DPolygon::getB2DRange() const
|
||||
{
|
||||
return mpPolygon->getB2DRange(*this);
|
||||
}
|
||||
@@ -1540,6 +1568,26 @@ namespace basegfx
|
||||
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
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
@@ -166,6 +166,26 @@ public:
|
||||
maPolygons.end(),
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
// 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)$/b2drange.obj \
|
||||
$(SLO)$/b2xrange.obj \
|
||||
$(SLO)$/b2dmultirange.obj \
|
||||
$(SLO)$/b2dpolyrange.obj \
|
||||
$(SLO)$/b2drangeclipper.obj \
|
||||
$(SLO)$/b3drange.obj
|
||||
|
||||
# --- Targets ----------------------------------
|
||||
|
@@ -41,7 +41,9 @@
|
||||
#include <basegfx/curve/b2dcubicbezier.hxx>
|
||||
#include <basegfx/curve/b2dbeziertools.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/color/bcolor.hxx>
|
||||
#include <basegfx/color/bcolortools.hxx>
|
||||
@@ -56,214 +58,6 @@ using namespace ::basegfx;
|
||||
|
||||
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
|
||||
{
|
||||
@@ -505,6 +299,39 @@ public:
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
}; // 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
|
||||
{
|
||||
private:
|
||||
@@ -1618,8 +1445,9 @@ public:
|
||||
}; // class b2dvector
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
//CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(basegfx2d::b2dmultirange, "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::b2dcubicbezier, "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 : _cppunit.mk
|
||||
|
||||
.IF "$(verbose)"!="" || "$(VERBOSE)"!=""
|
||||
CDEFS+= -DVERBOSE
|
||||
.ENDIF
|
||||
|
||||
# --- Enable testshl2 execution in normal build ------------------------
|
||||
|
||||
$(MISC)$/unittest_succeeded : $(SHL1TARGETN)
|
||||
|
Reference in New Issue
Block a user