summaryrefslogtreecommitdiff
path: root/basegfx/source/polygon
diff options
context:
space:
mode:
authorPascal Junck <pjunck@openoffice.org>2004-11-03 07:37:33 +0000
committerPascal Junck <pjunck@openoffice.org>2004-11-03 07:37:33 +0000
commit25f5ffb3ab1102eabe0e2a6397a3927a3e844174 (patch)
tree920e544ade753d6a9ba9a390b84f26a75c7380a1 /basegfx/source/polygon
parent58b002db3346dcb37e5b9f9ee18ad3e4fd1c341c (diff)
INTEGRATION: CWS aw019 (1.1.2); FILE ADDED
2004/10/14 12:28:18 aw 1.1.2.2: #i34831# 2004/10/13 14:01:17 aw 1.1.2.1: #i34831#
Diffstat (limited to 'basegfx/source/polygon')
-rw-r--r--basegfx/source/polygon/b2dlinegeometry.cxx487
1 files changed, 487 insertions, 0 deletions
diff --git a/basegfx/source/polygon/b2dlinegeometry.cxx b/basegfx/source/polygon/b2dlinegeometry.cxx
new file mode 100644
index 000000000000..101e85277a28
--- /dev/null
+++ b/basegfx/source/polygon/b2dlinegeometry.cxx
@@ -0,0 +1,487 @@
+/*************************************************************************
+ *
+ * $RCSfile: b2dlinegeometry.cxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: pjunck $ $Date: 2004-11-03 08:37:33 $
+ *
+ * The Contents of this file are made available subject to the terms of
+ * either of the following licenses
+ *
+ * - GNU Lesser General Public License Version 2.1
+ * - Sun Industry Standards Source License Version 1.1
+ *
+ * Sun Microsystems Inc., October, 2000
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2000 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library 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 for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ *
+ * Sun Industry Standards Source License Version 1.1
+ * =================================================
+ * The contents of this file are subject to the Sun Industry Standards
+ * Source License Version 1.1 (the "License"); You may not use this file
+ * except in compliance with the License. You may obtain a copy of the
+ * License at http://www.openoffice.org/license.html.
+ *
+ * Software provided under this License is provided on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+ * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
+ * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
+ * See the License for the specific provisions governing your rights and
+ * obligations concerning the Software.
+ *
+ * The Initial Developer of the Original Code is: Sun Microsystems, Inc.
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * Contributor(s): _______________________________________
+ *
+ *
+ ************************************************************************/
+
+#ifndef _OSL_DIAGNOSE_H_
+#include <osl/diagnose.h>
+#endif
+
+#ifndef _BGFX_POLYGON_B2DLINEGEOMETRY_HXX
+#include <basegfx/polygon/b2dlinegeometry.hxx>
+#endif
+
+#ifndef _BGFX_POINT_B2DPOINT_HXX
+#include <basegfx/point/b2dpoint.hxx>
+#endif
+
+#ifndef _BGFX_VECTOR_B2DVECTOR_HXX
+#include <basegfx/vector/b2dvector.hxx>
+#endif
+
+#ifndef _BGFX_POLYGON_B2DPOLYGONTOOLS_HXX
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#endif
+
+#ifndef _BGFX_POLYPOLYGON_B2DPOLYGONTOOLS_HXX
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#endif
+
+#ifndef _BGFX_RANGE_B2DRANGE_HXX
+#include <basegfx/range/b2drange.hxx>
+#endif
+
+#ifndef _BGFX_MATRIX_B2DHOMMATRIX_HXX
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#endif
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace basegfx
+{
+ // anonymus namespace for local helpers
+ namespace
+ {
+ // create area geometry for given edge. Edge is defined with the
+ // points rEdgeStart and rEdgeEnd. fHalfLineWidth defines the relative width.
+ // The created polygon will be positively oriented and free of
+ // self intersections.
+ // bCreateInBetweenPoints defines if EdgeStart and EdgeEnd themselves will
+ // be added (see comment in implementation).
+ B2DPolygon createAreaGeometryForEdge(
+ const B2DPoint& rEdgeStart,
+ const B2DPoint& rEdgeEnd,
+ double fHalfLineWidth,
+ bool bCreateInBetweenPoints)
+ {
+ OSL_ENSURE(fHalfLineWidth > 0.0, "createAreaGeometryForEdge: LineWidth too small (!)");
+ B2DPolygon aRetval;
+
+ // get perpendicular vector for reaching the outer edges
+ const B2DVector aEdgeVector(rEdgeEnd - rEdgeStart);
+ B2DVector aPerpendEdgeVector(getNormalizedPerpendicular(aEdgeVector));
+ aPerpendEdgeVector *= fHalfLineWidth;
+
+ // create polygon for edge
+ // Unfortunately, while it would be geometrically correct to not add
+ // the in-between points rEdgeEnd and rEdgeStart, it leads to rounding
+ // errors when converting to integer polygon coordiates for painting.
+ aRetval.append(rEdgeStart - aPerpendEdgeVector);
+ aRetval.append(rEdgeEnd - aPerpendEdgeVector);
+
+ if(bCreateInBetweenPoints)
+ {
+ aRetval.append(rEdgeEnd);
+ }
+
+ aRetval.append(rEdgeEnd + aPerpendEdgeVector);
+ aRetval.append(rEdgeStart + aPerpendEdgeVector);
+
+ if(bCreateInBetweenPoints)
+ {
+ aRetval.append(rEdgeStart);
+ }
+
+ aRetval.setClosed(true);
+
+#ifdef DBG_UTIL
+ // check orientation (debug only)
+ if(tools::getOrientation(aRetval) == ORIENTATION_NEGATIVE)
+ {
+ OSL_ENSURE(false, "createAreaGeometryForEdge: orientation of return value is negative (!)");
+ }
+#endif
+
+ return aRetval;
+ }
+
+ // create join polygon for given angle. Angle is defined with the
+ // points rLeft, rCenter and rRight. The given join type defines how
+ // the join segment will be created. fHalfLineWidth defines the relative width.
+ // fDegreeStepWidth is used when rounding edges.
+ // fMiterMinimumAngle is used to define when miter is forced to bevel.
+ // The created polygon will be positively or neuteral oriented and free of
+ // self intersections.
+ B2DPolygon createAreaGeometryForJoin(
+ const B2DPoint& rLeft,
+ const B2DPoint& rCenter,
+ const B2DPoint& rRight,
+ double fHalfLineWidth,
+ tools::B2DLineJoin eJoin,
+ double fDegreeStepWidth,
+ double fMiterMinimumAngle)
+ {
+ OSL_ENSURE(fHalfLineWidth > 0.0, "createAreaGeometryForJoin: LineWidth too small (!)");
+ OSL_ENSURE(fDegreeStepWidth > 0.0, "createAreaGeometryForJoin: DegreeStepWidth too small (!)");
+ OSL_ENSURE(tools::B2DLINEJOIN_NONE != eJoin, "createAreaGeometryForJoin: B2DLINEJOIN_NONE not allowed (!)");
+ B2DPolygon aRetval;
+
+ // get perpendicular vector for left and right
+ const B2DVector aLeftVector(rCenter - rLeft);
+ B2DVector aPerpendLeftVector(getNormalizedPerpendicular(aLeftVector));
+ const B2DVector aRightVector(rRight - rCenter);
+ B2DVector aPerpendRightVector(getNormalizedPerpendicular(aRightVector));
+
+ // get vector orientation
+ B2VectorOrientation aOrientation(getOrientation(aPerpendLeftVector, aPerpendRightVector));
+
+ if(ORIENTATION_NEUTRAL != aOrientation)
+ {
+ // prepare perpend vectors to be able to go from left to right.
+ // also multiply with fHalfLineWidth to get geometric vectors with correct length
+ if(ORIENTATION_POSITIVE == aOrientation)
+ {
+ // mirror to have them above the edge vectors
+ const double fNegativeHalfLineWidth(-fHalfLineWidth);
+ aPerpendLeftVector *= fNegativeHalfLineWidth;
+ aPerpendRightVector *= fNegativeHalfLineWidth;
+ }
+ else
+ {
+ // exchange left and right
+ const B2DVector aTemp(aPerpendLeftVector.getX() * fHalfLineWidth, aPerpendLeftVector.getY() * fHalfLineWidth);
+ aPerpendLeftVector.setX(aPerpendRightVector.getX() * fHalfLineWidth);
+ aPerpendLeftVector.setY(aPerpendRightVector.getY() * fHalfLineWidth);
+ aPerpendRightVector = aTemp;
+ }
+
+ // test if for Miter, the angle is too small
+ if(tools::B2DLINEJOIN_MITER == eJoin)
+ {
+ const double fAngle(fabs(aPerpendLeftVector.angle(aPerpendRightVector)));
+
+ if((F_PI - fAngle) < (15.0 * F_PI180))
+ {
+ // force to bevel
+ eJoin = tools::B2DLINEJOIN_BEVEL;
+ }
+ }
+
+ // create specific edge polygon
+ switch(eJoin)
+ {
+ case tools::B2DLINEJOIN_MIDDLE :
+ case tools::B2DLINEJOIN_BEVEL :
+ {
+ // create polygon for edge, go from left to right
+ aRetval.append(rCenter);
+ aRetval.append(rCenter + aPerpendLeftVector);
+ aRetval.append(rCenter + aPerpendRightVector);
+ aRetval.setClosed(true);
+
+ break;
+ }
+ case tools::B2DLINEJOIN_MITER :
+ {
+ // create first polygon part for edge, go from left to right
+ aRetval.append(rCenter);
+ aRetval.append(rCenter + aPerpendLeftVector);
+
+ double fCutPos(0.0);
+ const B2DPoint aLeftCutPoint(rCenter + aPerpendLeftVector);
+ const B2DPoint aRightCutPoint(rCenter + aPerpendRightVector);
+
+ if(ORIENTATION_POSITIVE == aOrientation)
+ {
+ tools::findCut(aLeftCutPoint, aLeftVector, aRightCutPoint, -aRightVector, CUTFLAG_ALL, &fCutPos);
+
+ if(0.0 != fCutPos)
+ {
+ const B2DPoint aCutPoint(
+ interpolate(aLeftCutPoint, aLeftCutPoint + aLeftVector, fCutPos));
+ aRetval.append(aCutPoint);
+ }
+ }
+ else
+ {
+ // peroendiculars are exchanged, also use exchanged EdgeVectors
+ tools::findCut(aLeftCutPoint, -aRightVector, aRightCutPoint, aLeftVector, CUTFLAG_ALL, &fCutPos);
+
+ if(0.0 != fCutPos)
+ {
+ const B2DPoint aCutPoint(
+ interpolate(aLeftCutPoint, aLeftCutPoint - aRightVector, fCutPos));
+ aRetval.append(aCutPoint);
+ }
+ }
+
+ // create last polygon part for edge
+ aRetval.append(rCenter + aPerpendRightVector);
+ aRetval.setClosed(true);
+
+ break;
+ }
+ case tools::B2DLINEJOIN_ROUND :
+ {
+ // create first polygon part for edge, go from left to right
+ aRetval.append(rCenter);
+ aRetval.append(rCenter + aPerpendLeftVector);
+
+ // get angle and prepare
+ double fAngle(aPerpendLeftVector.angle(aPerpendRightVector));
+ const bool bNegative(fAngle < 0.0);
+ if(bNegative)
+ {
+ fAngle = fabs(fAngle);
+ }
+
+ // substract first step, first position is added to
+ // the polygon yet
+ fAngle -= fDegreeStepWidth;
+
+ // create points as long as angle is > 0.0
+ if(fAngle > 0.0)
+ {
+ // get start angle
+ double fAngleOfLeftPerpendVector(
+ atan2(aPerpendLeftVector.getY(), aPerpendLeftVector.getX()));
+
+ while(fAngle > 0.0)
+ {
+ // calculate rotated vector
+ fAngleOfLeftPerpendVector += (bNegative ? -fDegreeStepWidth : fDegreeStepWidth);
+ const B2DVector aRotatedVector(
+ rCenter.getX() + (cos(fAngleOfLeftPerpendVector) * fHalfLineWidth),
+ rCenter.getY() + (sin(fAngleOfLeftPerpendVector) * fHalfLineWidth));
+
+ // add point
+ aRetval.append(aRotatedVector);
+
+ // substract next step
+ fAngle -= fDegreeStepWidth;
+ }
+ }
+
+ // create last polygon part for edge
+ aRetval.append(rCenter + aPerpendRightVector);
+ aRetval.setClosed(true);
+
+ break;
+ }
+ }
+ }
+
+#ifdef DBG_UTIL
+ // check orientation (debug only)
+ if(tools::getOrientation(aRetval) == ORIENTATION_NEGATIVE)
+ {
+ OSL_ENSURE(false, "createAreaGeometryForJoin: orientation of return value is negative (!)");
+ }
+#endif
+
+ return aRetval;
+ }
+ } // end of anonymus namespace
+
+ namespace tools
+ {
+ B2DPolyPolygon createAreaGeometryForPolygon(const B2DPolygon& rCandidate,
+ double fHalfLineWidth,
+ B2DLineJoin eJoin,
+ double fDegreeStepWidth,
+ double fMiterMinimumAngle)
+ {
+ OSL_ENSURE(fHalfLineWidth > 0.0, "createAreaGeometryForPolygon: LineWidth too small (!)");
+ OSL_ENSURE(fDegreeStepWidth > 0.0, "createAreaGeometryForPolygon: DegreeStepWidth too small (!)");
+ B2DPolyPolygon aRetval;
+ const sal_uInt32 nCount(rCandidate.count());
+
+ if(rCandidate.isClosed())
+ {
+ const bool bNeedToCreateJoinPolygon(B2DLINEJOIN_NONE != eJoin);
+ bool bLastNeededToCreateJoinPolygon(false);
+
+ for(sal_uInt32 a(0L); a < nCount; a++)
+ {
+ // get left, right, prev and next positions for edge
+ B2DPoint aEdgeStart(rCandidate.getB2DPoint(a));
+ B2DPoint aEdgeEnd(rCandidate.getB2DPoint((a + 1L) % nCount));
+
+ // create geometry for edge and add to result
+ B2DPolygon aEdgePolygon(createAreaGeometryForEdge(
+ aEdgeStart, aEdgeEnd, fHalfLineWidth,
+ bNeedToCreateJoinPolygon || bLastNeededToCreateJoinPolygon));
+ aRetval.append(aEdgePolygon);
+
+ if(bNeedToCreateJoinPolygon)
+ {
+ // create fill polygon for linejoin and add to result
+ B2DPoint aNextEdge(rCandidate.getB2DPoint((a + 2L) % nCount));
+ B2DPolygon aJoinPolygon(createAreaGeometryForJoin(
+ aEdgeStart, aEdgeEnd, aNextEdge, fHalfLineWidth, eJoin, fDegreeStepWidth, fMiterMinimumAngle));
+
+ if(aRetval.count())
+ {
+ aRetval.append(aJoinPolygon);
+ }
+ }
+
+ bLastNeededToCreateJoinPolygon = bNeedToCreateJoinPolygon;
+ }
+ }
+ else if(nCount > 1L)
+ {
+ bool bLastNeededToCreateJoinPolygon(false);
+
+ for(sal_uInt32 a(0L); a < nCount - 1L; a++)
+ {
+ // get left, right positions for edge
+ B2DPoint aEdgeStart(rCandidate.getB2DPoint(a));
+ B2DPoint aEdgeEnd(rCandidate.getB2DPoint(a + 1L));
+ const bool bNeedToCreateJoinPolygon((a + 2L < nCount) && B2DLINEJOIN_NONE != eJoin);
+
+ // create geometry for edge and add to result
+ B2DPolygon aEdgePolygon(
+ createAreaGeometryForEdge(aEdgeStart, aEdgeEnd, fHalfLineWidth,
+ bNeedToCreateJoinPolygon || bLastNeededToCreateJoinPolygon));
+ aRetval.append(aEdgePolygon);
+
+ // test if next exists
+ if(bNeedToCreateJoinPolygon)
+ {
+ // create fill polygon for linejoin and add to result
+ B2DPoint aNextEdge(rCandidate.getB2DPoint((a + 2L)));
+ B2DPolygon aJoinPolygon(createAreaGeometryForJoin(
+ aEdgeStart, aEdgeEnd, aNextEdge, fHalfLineWidth, eJoin, fDegreeStepWidth, fMiterMinimumAngle));
+
+ if(aRetval.count())
+ {
+ aRetval.append(aJoinPolygon);
+ }
+ }
+
+ bLastNeededToCreateJoinPolygon = bNeedToCreateJoinPolygon;
+ }
+ }
+
+ return aRetval;
+ }
+
+ B2DPolyPolygon createAreaGeometryForLineStartEnd(
+ const B2DPolygon& rCandidate,
+ const B2DPolyPolygon& rArrow,
+ bool bStart,
+ double fWidth,
+ double fDockingPosition, // 0->top, 1->bottom
+ double* pConsumedLength)
+ {
+ OSL_ENSURE(rCandidate.count() > 1L, "createAreaGeometryForLineStartEnd: Line polygon has too less points too small (!)");
+ OSL_ENSURE(rArrow.count() > 0L, "createAreaGeometryForLineStartEnd: No arrow PolyPolygon (!)");
+ OSL_ENSURE(fWidth > 0.0, "createAreaGeometryForLineStartEnd: Width too small (!)");
+ OSL_ENSURE(fDockingPosition >= 0.0 && fDockingPosition <= 1.0,
+ "createAreaGeometryForLineStartEnd: fDockingPosition out of range [0.0 .. 1.0] (!)");
+
+ // init return value from arrow
+ B2DPolyPolygon aRetval(rArrow);
+
+ // get size of the arrow
+ const B2DRange aArrowSize(getRange(rArrow));
+
+ // build ArrowTransform
+ B2DHomMatrix aArrowTransform;
+
+ // center in X, align with axis in Y
+ aArrowTransform.translate(-aArrowSize.getCenter().getX(), -aArrowSize.getMinimum().getY());
+
+ // scale to target size
+ const double fArrowScale(fWidth / (aArrowSize.getRange().getX()));
+ aArrowTransform.scale(fArrowScale, fArrowScale);
+
+ // get arrow size in Y
+ B2DPoint aUpperCenter(aArrowSize.getCenter().getX(), aArrowSize.getMaximum().getY());
+ aUpperCenter *= aArrowTransform;
+ const double fArrowYLength(B2DVector(aUpperCenter).getLength());
+
+ // move arrow to have docking position centered
+ aArrowTransform.translate(0.0, -fArrowYLength * fDockingPosition);
+
+ // get the polygon vector we want to plant this arrow on
+ const double fCandidateLength(getLength(rCandidate));
+ const double fConsumedLength(fArrowYLength * (1.0 - fDockingPosition));
+ const B2DVector aHead(rCandidate.getB2DPoint((bStart) ? 0L : rCandidate.count() - 1L));
+ const B2DVector aTail(getPositionAbsolute(rCandidate,
+ (bStart) ? fConsumedLength : fCandidateLength - fConsumedLength, fCandidateLength));
+
+ // from that vector, take the needed rotation and add rotate for arrow to transformation
+ const B2DVector aTargetDirection(aHead - aTail);
+ const double fRotation(atan2(aTargetDirection.getY(), aTargetDirection.getX()) + (90.0 * F_PI180));
+
+ // rotate around docking position
+ aArrowTransform.rotate(fRotation);
+
+ // move arrow docking position to polygon head
+ aArrowTransform.translate(aHead.getX(), aHead.getY());
+
+ // transform retval and close
+ aRetval.transform(aArrowTransform);
+ aRetval.setClosed(true);
+
+ // if pConsumedLength is asked for, fill it
+ if(pConsumedLength)
+ {
+ *pConsumedLength = fConsumedLength;
+ }
+
+ return aRetval;
+ }
+ } // end of namespace tools
+} // end of namespace basegfx
+
+//////////////////////////////////////////////////////////////////////////////
+// eof