Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/basegfx/source/polygon/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 33 kB image not shown  

Quelle  b3dpolygontools.cxx   Sprache: C

 
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 .
 */


#include <osl/diagnose.h>
#include <basegfx/polygon/b3dpolygontools.hxx>
#include <basegfx/polygon/b3dpolygon.hxx>
#include <basegfx/polygon/b3dpolypolygon.hxx>
#include <basegfx/numeric/ftools.hxx>
#include <basegfx/range/b3drange.hxx>
#include <basegfx/point/b2dpoint.hxx>
#include <basegfx/tuple/b3ituple.hxx>
#include <cassert>
#include <numeric>

namespace basegfx::utils
{
        // B3DPolygon tools
        void checkClosed(B3DPolygon& rCandidate)
        {
            while(rCandidate.count() > 1
                && rCandidate.getB3DPoint(0).equal(rCandidate.getB3DPoint(rCandidate.count() - 1)))
            {
                rCandidate.setClosed(true);
                rCandidate.remove(rCandidate.count() - 1);
            }
        }

        sal_uInt32 getIndexOfSuccessor(sal_uInt32 nIndex, const B3DPolygon& rCandidate)
        {
            OSL_ENSURE(nIndex < rCandidate.count(), "getIndexOfPredecessor: Access to polygon out of range (!)");

            if(nIndex + 1 < rCandidate.count())
            {
                return nIndex + 1;
            }
            else
            {
                return 0;
            }
        }

        B3DRange getRange(const B3DPolygon& rCandidate)
        {
            B3DRange aRetval;
            const sal_uInt32 nPointCount(rCandidate.count());

            for(sal_uInt32 a(0); a < nPointCount; a++)
            {
                const B3DPoint aTestPoint(rCandidate.getB3DPoint(a));
                aRetval.expand(aTestPoint);
            }

            return aRetval;
        }

        double getLength(const B3DPolygon& rCandidate)
        {
            double fRetval(0.0);
            const sal_uInt32 nPointCount(rCandidate.count());

            if(nPointCount > 1)
            {
                const sal_uInt32 nLoopCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1);

                for(sal_uInt32 a(0); a < nLoopCount; a++)
                {
                    const sal_uInt32 nNextIndex(getIndexOfSuccessor(a, rCandidate));
                    const B3DPoint aCurrentPoint(rCandidate.getB3DPoint(a));
                    const B3DPoint aNextPoint(rCandidate.getB3DPoint(nNextIndex));
                    const B3DVector aVector(aNextPoint - aCurrentPoint);
                    fRetval += aVector.getLength();
                }
            }

            return fRetval;
        }

        void applyLineDashing(
            const B3DPolygon& rCandidate,
            const std::vector<double>& rDotDashArray,
            B3DPolyPolygon* pLineTarget,
            double fDotDashLength)
        {
            // clear targets in any case
            if(pLineTarget)
            {
                pLineTarget->clear();
            }

            // call version that uses callbacks
            applyLineDashing(
                rCandidate,
                rDotDashArray,
                // provide callback as lambda
                (!pLineTarget
                    ? std::function<void(const basegfx::B3DPolygon&)>()
                    : [&pLineTarget](const basegfx::B3DPolygon& rSnippet){ pLineTarget->append(rSnippet); }),
                fDotDashLength);
        }

        static void implHandleSnippet(
            const B3DPolygon& rSnippet,
            const std::function<void(const basegfx::B3DPolygon& rSnippet)>& rTargetCallback,
            B3DPolygon& rFirst,
            B3DPolygon& rLast)
        {
            if(rSnippet.isClosed())
            {
                if(!rFirst.count())
                {
                    rFirst = rSnippet;
                }
                else
                {
                    if(rLast.count())
                    {
                        rTargetCallback(rLast);
                    }

                    rLast = rSnippet;
                }
            }
            else
            {
                rTargetCallback(rSnippet);
            }
        }

        static void implHandleFirstLast(
            const std::function<void(const basegfx::B3DPolygon& rSnippet)>& rTargetCallback,
            B3DPolygon& rFirst,
            B3DPolygon& rLast)
        {
            if(rFirst.count() && rLast.count()
                && rFirst.getB3DPoint(0).equal(rLast.getB3DPoint(rLast.count() - 1)))
            {
                // start of first and end of last are the same -> merge them
                rLast.append(rFirst);
                rLast.removeDoublePoints();
                rFirst.clear();
            }

            if(rLast.count())
            {
                rTargetCallback(rLast);
            }

            if(rFirst.count())
            {
                rTargetCallback(rFirst);
            }
        }

        void applyLineDashing(
            const B3DPolygon& rCandidate,
            const std::vector<double>& rDotDashArray,
            const std::function<void(const basegfx::B3DPolygon& rSnippet)>& rLineTargetCallback,
            double fDotDashLength)
        {
            const sal_uInt32 nPointCount(rCandidate.count());
            const sal_uInt32 nDotDashCount(rDotDashArray.size());

            if(fDotDashLength <= 0.0)
            {
                fDotDashLength = std::accumulate(rDotDashArray.begin(), rDotDashArray.end(), 0.0);
            }

            if(fDotDashLength <= 0.0 || !rLineTargetCallback || !nPointCount)
            {
                // parameters make no sense, just add source to targets
                if (rLineTargetCallback)
                    rLineTargetCallback(rCandidate);
                return;
            }

            // precalculate maximal acceptable length of candidate polygon assuming
            // we want to create a maximum of fNumberOfAllowedSnippets. In 3D
            // use less for fNumberOfAllowedSnippets, ca. 6553.6, double due to line & gap.
            // Less in 3D due to potentially blowing up to rounded line segments.
            static const double fNumberOfAllowedSnippets(6553.5 * 2.0);
            const double fAllowedLength((fNumberOfAllowedSnippets * fDotDashLength) / double(rDotDashArray.size()));
            const double fCandidateLength(basegfx::utils::getLength(rCandidate));
            std::vector<double> aDotDashArray(rDotDashArray);

            if(fCandidateLength > fAllowedLength)
            {
                // we would produce more than fNumberOfAllowedSnippets, so
                // adapt aDotDashArray to exactly produce assumed number. Also
                // assert this to let the caller know about it.
                // If this asserts: Please think about checking your DotDashArray
                // before calling this function or evtl. use the callback version
                // to *not* produce that much of data. Even then, you may still
                // think about producing too much runtime (!)
                assert(true && "applyLineDashing: potentially too expensive to do the requested dismantle - please consider stretched LineDash pattern (!)");

                // calculate correcting factor, apply to aDotDashArray and fDotDashLength
                // to enlarge these as needed
                const double fFactor(fCandidateLength / fAllowedLength);
                std::for_each(aDotDashArray.begin(), aDotDashArray.end(), [&fFactor](double &f){ f *= fFactor; });
            }

            // prepare current edge's start
            B3DPoint aCurrentPoint(rCandidate.getB3DPoint(0));
            const bool bIsClosed(rCandidate.isClosed());
            const sal_uInt32 nEdgeCount(bIsClosed ? nPointCount : nPointCount - 1);

            // prepare DotDashArray iteration and the line/gap switching bool
            sal_uInt32 nDotDashIndex(0);
            bool bIsLine(true);
            double fDotDashMovingLength(aDotDashArray[0]);
            B3DPolygon aSnippet;

            // remember 1st and last snippets to try to merge after execution
            // is complete and hand to callback
            B3DPolygon aFirstLine, aLastLine;

            // iterate over all edges
            for(sal_uInt32 a(0); a < nEdgeCount; a++)
            {
                // update current edge
                const sal_uInt32 nNextIndex((a + 1) % nPointCount);
                const B3DPoint aNextPoint(rCandidate.getB3DPoint(nNextIndex));
                const double fEdgeLength(B3DVector(aNextPoint - aCurrentPoint).getLength());

                if(!fTools::equalZero(fEdgeLength))
                {
                    double fLastDotDashMovingLength(0.0);
                    while(fTools::less(fDotDashMovingLength, fEdgeLength))
                    {
                        // new split is inside edge, create and append snippet [fLastDotDashMovingLength, fDotDashMovingLength]
                        if(bIsLine)
                        {
                            if(!aSnippet.count())
                            {
                                aSnippet.append(interpolate(aCurrentPoint, aNextPoint, fLastDotDashMovingLength / fEdgeLength));
                            }

                            aSnippet.append(interpolate(aCurrentPoint, aNextPoint, fDotDashMovingLength / fEdgeLength));

                            implHandleSnippet(aSnippet, rLineTargetCallback, aFirstLine, aLastLine);

                            aSnippet.clear();
                        }

                        // prepare next DotDashArray step and flip line/gap flag
                        fLastDotDashMovingLength = fDotDashMovingLength;
                        fDotDashMovingLength += aDotDashArray[(++nDotDashIndex) % nDotDashCount];
                        bIsLine = !bIsLine;
                    }

                    // append snippet [fLastDotDashMovingLength, fEdgeLength]
                    if(bIsLine)
                    {
                        if(!aSnippet.count())
                        {
                            aSnippet.append(interpolate(aCurrentPoint, aNextPoint, fLastDotDashMovingLength / fEdgeLength));
                        }

                        aSnippet.append(aNextPoint);
                    }

                    // prepare move to next edge
                    fDotDashMovingLength -= fEdgeLength;
                }

                // prepare next edge step (end point gets new start point)
                aCurrentPoint = aNextPoint;
            }

            // append last intermediate results (if exists)
            if(aSnippet.count())
            {
                if(bIsLine)
                {
                    implHandleSnippet(aSnippet, rLineTargetCallback, aFirstLine, aLastLine);
                }
            }

            if(bIsClosed)
            {
                implHandleFirstLast(rLineTargetCallback, aFirstLine, aLastLine);
            }
        }

        B3DPolygon applyDefaultNormalsSphere( const B3DPolygon& rCandidate, const B3DPoint&&nbsp;rCenter)
        {
            B3DPolygon aRetval(rCandidate);

            for(sal_uInt32 a(0); a < aRetval.count(); a++)
            {
                B3DVector aVector(aRetval.getB3DPoint(a) - rCenter);
                aVector.normalize();
                aRetval.setNormal(a, aVector);
            }

            return aRetval;
        }

        B3DPolygon invertNormals( const B3DPolygon& rCandidate)
        {
            B3DPolygon aRetval(rCandidate);

            if(aRetval.areNormalsUsed())
            {
                for(sal_uInt32 a(0); a < aRetval.count(); a++)
                {
                    aRetval.setNormal(a, -aRetval.getNormal(a));
                }
            }

            return aRetval;
        }

        B3DPolygon applyDefaultTextureCoordinatesParallel( const B3DPolygon& rCandidate, const B3DRange& rRange, bool bChangeX, bool bChangeY)
        {
            B3DPolygon aRetval(rCandidate);

            if(bChangeX || bChangeY)
            {
                // create projection of standard texture coordinates in (X, Y) onto
                // the 3d coordinates straight
                const double fWidth(rRange.getWidth());
                const double fHeight(rRange.getHeight());
                const bool bWidthSet(!fTools::equalZero(fWidth));
                const bool bHeightSet(!fTools::equalZero(fHeight));
                const double fOne(1.0);

                for(sal_uInt32 a(0); a < aRetval.count(); a++)
                {
                    const B3DPoint aPoint(aRetval.getB3DPoint(a));
                    B2DPoint aTextureCoordinate(aRetval.getTextureCoordinate(a));

                    if(bChangeX)
                    {
                        if(bWidthSet)
                        {
                            aTextureCoordinate.setX((aPoint.getX() - rRange.getMinX()) / fWidth);
                        }
                        else
                        {
                            aTextureCoordinate.setX(0.0);
                        }
                    }

                    if(bChangeY)
                    {
                        if(bHeightSet)
                        {
                            aTextureCoordinate.setY(fOne - ((aPoint.getY() - rRange.getMinY()) / fHeight));
                        }
                        else
                        {
                            aTextureCoordinate.setY(fOne);
                        }
                    }

                    aRetval.setTextureCoordinate(a, aTextureCoordinate);
                }
            }

            return aRetval;
        }

        B3DPolygon applyDefaultTextureCoordinatesSphere( const B3DPolygon& rCandidate, const B3DPoint& rCenter, bool bChangeX, bool bChangeY)
        {
            B3DPolygon aRetval(rCandidate);

            if(bChangeX || bChangeY)
            {
                // create texture coordinates using sphere projection to cartesian coordinates,
                // use object's center as base
                const double fOne(1.0);
                const sal_uInt32 nPointCount(aRetval.count());
                bool bPolarPoints(false);
                sal_uInt32 a;

                // create center cartesian coordinates to have a possibility to decide if on boundary
                // transitions which value to choose
                const B3DRange aPlaneRange(getRange(rCandidate));
                const B3DPoint aPlaneCenter(aPlaneRange.getCenter() - rCenter);
                const double fXCenter(fOne - ((atan2(aPlaneCenter.getZ(), aPlaneCenter.getX()) + M_PI) / (2 * M_PI)));

                for(a = 0; a < nPointCount; a++)
                {
                    const B3DVector aVector(aRetval.getB3DPoint(a) - rCenter);
                    const double fY(fOne - ((atan2(aVector.getY(), aVector.getXZLength()) + M_PI_2) / M_PI));
                    B2DPoint aTexCoor(aRetval.getTextureCoordinate(a));

                    if(fTools::equalZero(fY))
                    {
                        // point is a north polar point, no useful X-coordinate can be created.
                        if(bChangeY)
                        {
                            aTexCoor.setY(0.0);

                            if(bChangeX)
                            {
                                bPolarPoints = true;
                            }
                        }
                    }
                    else if(fTools::equal(fY, fOne))
                    {
                        // point is a south polar point, no useful X-coordinate can be created. Set
                        // Y-coordinate, though
                        if(bChangeY)
                        {
                            aTexCoor.setY(fOne);

                            if(bChangeX)
                            {
                                bPolarPoints = true;
                            }
                        }
                    }
                    else
                    {
                        double fX(fOne - ((atan2(aVector.getZ(), aVector.getX()) + M_PI) / (2 * M_PI)));

                        // correct cartesian point coordinate dependent from center value
                        if(fX > fXCenter + 0.5)
                        {
                            fX -= fOne;
                        }
                        else if(fX < fXCenter - 0.5)
                        {
                            fX += fOne;
                        }

                        if(bChangeX)
                        {
                            aTexCoor.setX(fX);
                        }

                        if(bChangeY)
                        {
                            aTexCoor.setY(fY);
                        }
                    }

                    aRetval.setTextureCoordinate(a, aTexCoor);
                }

                if(bPolarPoints)
                {
                    // correct X-texture coordinates if polar points are contained. Those
                    // coordinates cannot be correct, so use prev or next X-coordinate
                    for(a = 0; a < nPointCount; a++)
                    {
                        B2DPoint aTexCoor(aRetval.getTextureCoordinate(a));

                        if(fTools::equalZero(aTexCoor.getY()) || fTools::equal(aTexCoor.getY(), fOne))
                        {
                            // get prev, next TexCoor and test for pole
                            const B2DPoint aPrevTexCoor(aRetval.getTextureCoordinate(a ? a - 1 : nPointCount - 1));
                            const B2DPoint aNextTexCoor(aRetval.getTextureCoordinate((a + 1) % nPointCount));
                            const bool bPrevPole(fTools::equalZero(aPrevTexCoor.getY()) || fTools::equal(aPrevTexCoor.getY(), fOne));
                            const bool bNextPole(fTools::equalZero(aNextTexCoor.getY()) || fTools::equal(aNextTexCoor.getY(), fOne));

                            if(!bPrevPole && !bNextPole)
                            {
                                // both no poles, mix them
                                aTexCoor.setX((aPrevTexCoor.getX() + aNextTexCoor.getX()) / 2.0);
                            }
                            else if(!bNextPole)
                            {
                                // copy next
                                aTexCoor.setX(aNextTexCoor.getX());
                            }
                            else
                            {
                                // copy prev, even if it's a pole, hopefully it is already corrected
                                aTexCoor.setX(aPrevTexCoor.getX());
                            }

                            aRetval.setTextureCoordinate(a, aTexCoor);
                        }
                    }
                }
            }

            return aRetval;
        }

        bool isInside(const B3DPolygon& rCandidate, const B3DPoint& rPoint, bool bWithBorder)
        {
            if(bWithBorder && isPointOnPolygon(rCandidate, rPoint))
            {
                return true;
            }
            else
            {
                bool bRetval(false);
                const B3DVector aPlaneNormal(rCandidate.getNormal());

                if(!aPlaneNormal.equalZero())
                {
                    const sal_uInt32 nPointCount(rCandidate.count());

                    if(nPointCount)
                    {
                        B3DPoint aCurrentPoint(rCandidate.getB3DPoint(nPointCount - 1));
                        const double fAbsX(fabs(aPlaneNormal.getX()));
                        const double fAbsY(fabs(aPlaneNormal.getY()));
                        const double fAbsZ(fabs(aPlaneNormal.getZ()));

                        if(fAbsX > fAbsY && fAbsX > fAbsZ)
                        {
                            // normal points mostly in X-Direction, use YZ-Polygon projection for check
                            // x -> y, y -> z
                            for(sal_uInt32 a(0); a < nPointCount; a++)
                            {
                                const B3DPoint aPreviousPoint(aCurrentPoint);
                                aCurrentPoint = rCandidate.getB3DPoint(a);

                                // cross-over in Z?
                                const bool bCompZA(fTools::more(aPreviousPoint.getZ(), rPoint.getZ()));
                                const bool bCompZB(fTools::more(aCurrentPoint.getZ(), rPoint.getZ()));

                                if(bCompZA != bCompZB)
                                {
                                    // cross-over in Y?
                                    const bool bCompYA(fTools::more(aPreviousPoint.getY(), rPoint.getY()));
                                    const bool bCompYB(fTools::more(aCurrentPoint.getY(), rPoint.getY()));

                                    if(bCompYA == bCompYB)
                                    {
                                        if(bCompYA)
                                        {
                                            bRetval = !bRetval;
                                        }
                                    }
                                    else
                                    {
                                        const double fCompare(
                                            aCurrentPoint.getY() - (aCurrentPoint.getZ() - rPoint.getZ()) *
                                            (aPreviousPoint.getY() - aCurrentPoint.getY()) /
                                            (aPreviousPoint.getZ() - aCurrentPoint.getZ()));

                                        if(fTools::more(fCompare, rPoint.getY()))
                                        {
                                            bRetval = !bRetval;
                                        }
                                    }
                                }
                            }
                        }
                        else if(fAbsY > fAbsX && fAbsY > fAbsZ)
                        {
                            // normal points mostly in Y-Direction, use XZ-Polygon projection for check
                            // x -> x, y -> z
                            for(sal_uInt32 a(0); a < nPointCount; a++)
                            {
                                const B3DPoint aPreviousPoint(aCurrentPoint);
                                aCurrentPoint = rCandidate.getB3DPoint(a);

                                // cross-over in Z?
                                const bool bCompZA(fTools::more(aPreviousPoint.getZ(), rPoint.getZ()));
                                const bool bCompZB(fTools::more(aCurrentPoint.getZ(), rPoint.getZ()));

                                if(bCompZA != bCompZB)
                                {
                                    // cross-over in X?
                                    const bool bCompXA(fTools::more(aPreviousPoint.getX(), rPoint.getX()));
                                    const bool bCompXB(fTools::more(aCurrentPoint.getX(), rPoint.getX()));

                                    if(bCompXA == bCompXB)
                                    {
                                        if(bCompXA)
                                        {
                                            bRetval = !bRetval;
                                        }
                                    }
                                    else
                                    {
                                        const double fCompare(
                                            aCurrentPoint.getX() - (aCurrentPoint.getZ() - rPoint.getZ()) *
                                            (aPreviousPoint.getX() - aCurrentPoint.getX()) /
                                            (aPreviousPoint.getZ() - aCurrentPoint.getZ()));

                                        if(fTools::more(fCompare, rPoint.getX()))
                                        {
                                            bRetval = !bRetval;
                                        }
                                    }
                                }
                            }
                        }
                        else
                        {
                            // normal points mostly in Z-Direction, use XY-Polygon projection for check
                            // x -> x, y -> y
                            for(sal_uInt32 a(0); a < nPointCount; a++)
                            {
                                const B3DPoint aPreviousPoint(aCurrentPoint);
                                aCurrentPoint = rCandidate.getB3DPoint(a);

                                // cross-over in Y?
                                const bool bCompYA(fTools::more(aPreviousPoint.getY(), rPoint.getY()));
                                const bool bCompYB(fTools::more(aCurrentPoint.getY(), rPoint.getY()));

                                if(bCompYA != bCompYB)
                                {
                                    // cross-over in X?
                                    const bool bCompXA(fTools::more(aPreviousPoint.getX(), rPoint.getX()));
                                    const bool bCompXB(fTools::more(aCurrentPoint.getX(), rPoint.getX()));

                                    if(bCompXA == bCompXB)
                                    {
                                        if(bCompXA)
                                        {
                                            bRetval = !bRetval;
                                        }
                                    }
                                    else
                                    {
                                        const double fCompare(
                                            aCurrentPoint.getX() - (aCurrentPoint.getY() - rPoint.getY()) *
                                            (aPreviousPoint.getX() - aCurrentPoint.getX()) /
                                            (aPreviousPoint.getY() - aCurrentPoint.getY()));

                                        if(fTools::more(fCompare, rPoint.getX()))
                                        {
                                            bRetval = !bRetval;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }

                return bRetval;
            }
        }

        bool isPointOnLine(const B3DPoint& rStart, const B3DPoint& rEnd, const B3DPoint&&nbsp;rCandidate, bool bWithPoints)
        {
            if(rCandidate.equal(rStart) || rCandidate.equal(rEnd))
            {
                // candidate is in epsilon around start or end -> inside
                return bWithPoints;
            }
            else if(rStart.equal(rEnd))
            {
                // start and end are equal, but candidate is outside their epsilon -> outside
                return false;
            }
            else
            {
                const B3DVector aEdgeVector(rEnd - rStart);
                const B3DVector aTestVector(rCandidate - rStart);

                if(areParallel(aEdgeVector, aTestVector))
                {
                    double fParamTestOnCurr(0.0);

                    if(aEdgeVector.getX() > aEdgeVector.getY())
                    {
                        if(aEdgeVector.getX() > aEdgeVector.getZ())
                        {
                            // X is biggest
                            fParamTestOnCurr = aTestVector.getX() / aEdgeVector.getX();
                        }
                        else
                        {
                            // Z is biggest
                            fParamTestOnCurr = aTestVector.getZ() / aEdgeVector.getZ();
                        }
                    }
                    else
                    {
                        if(aEdgeVector.getY() > aEdgeVector.getZ())
                        {
                            // Y is biggest
                            fParamTestOnCurr = aTestVector.getY() / aEdgeVector.getY();
                        }
                        else
                        {
                            // Z is biggest
                            fParamTestOnCurr = aTestVector.getZ() / aEdgeVector.getZ();
                        }
                    }

                    if(fParamTestOnCurr > 0.0 && fTools::less(fParamTestOnCurr, 1.0))
                    {
                        return true;
                    }
                }

                return false;
            }
        }

        bool isPointOnPolygon(const B3DPolygon& rCandidate, const B3DPoint& rPoint)
        {
            const sal_uInt32 nPointCount(rCandidate.count());

            if(nPointCount > 1)
            {
                const sal_uInt32 nLoopCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1);
                B3DPoint aCurrentPoint(rCandidate.getB3DPoint(0));

                for(sal_uInt32 a(0); a < nLoopCount; a++)
                {
                    const B3DPoint aNextPoint(rCandidate.getB3DPoint((a + 1) % nPointCount));

                    if(isPointOnLine(aCurrentPoint, aNextPoint, rPoint, true/*bWithPoints*/))
                    {
                        return true;
                    }

                    aCurrentPoint = aNextPoint;
                }
            }
            else if(nPointCount)
            {
                return rPoint.equal(rCandidate.getB3DPoint(0));
            }

            return false;
        }

        bool getCutBetweenLineAndPlane(const B3DVector& rPlaneNormal, const B3DPoint& rPlanePoint, const B3DPoint& rEdgeStart, const B3DPoint& rEdgeEnd, double& fCut)
        {
            if(!rPlaneNormal.equalZero() && !rEdgeStart.equal(rEdgeEnd))
            {
                const B3DVector aTestEdge(rEdgeEnd - rEdgeStart);
                const double fScalarEdge(rPlaneNormal.scalar(aTestEdge));

                if(!fTools::equalZero(fScalarEdge))
                {
                    const B3DVector aCompareEdge(rPlanePoint - rEdgeStart);
                    const double fScalarCompare(rPlaneNormal.scalar(aCompareEdge));

                    fCut = fScalarCompare / fScalarEdge;
                    return true;
                }
            }

            return false;
        }

        // snap points of horizontal or vertical edges to discrete values
        B3DPolygon snapPointsOfHorizontalOrVerticalEdges(const B3DPolygon& rCandidate)
        {
            const sal_uInt32 nPointCount(rCandidate.count());

            if(nPointCount > 1)
            {
                // Start by copying the source polygon to get a writeable copy. The closed state is
                // copied by aRetval's initialisation, too, so no need to copy it in this method
                B3DPolygon aRetval(rCandidate);

                // prepare geometry data. Get rounded from original
                B3ITuple aPrevTuple(basegfx::fround(rCandidate.getB3DPoint(nPointCount - 1)));
                B3DPoint aCurrPoint(rCandidate.getB3DPoint(0));
                B3ITuple aCurrTuple(basegfx::fround(aCurrPoint));

                // loop over all points. This will also snap the implicit closing edge
                // even when not closed, but that's no problem here
                for(sal_uInt32 a(0); a < nPointCount; a++)
                {
                    // get next point. Get rounded from original
                    const bool bLastRun(a + 1 == nPointCount);
                    const sal_uInt32 nNextIndex(bLastRun ? 0 : a + 1);
                    const B3DPoint aNextPoint(rCandidate.getB3DPoint(nNextIndex));
                    const B3ITuple aNextTuple(basegfx::fround(aNextPoint));

                    // get the states
                    const bool bPrevVertical(aPrevTuple.getX() == aCurrTuple.getX());
                    const bool bNextVertical(aNextTuple.getX() == aCurrTuple.getX());
                    const bool bPrevHorizontal(aPrevTuple.getY() == aCurrTuple.getY());
                    const bool bNextHorizontal(aNextTuple.getY() == aCurrTuple.getY());
                    const bool bSnapX(bPrevVertical || bNextVertical);
                    const bool bSnapY(bPrevHorizontal || bNextHorizontal);

                    if(bSnapX || bSnapY)
                    {
                        const B3DPoint aSnappedPoint(
                            bSnapX ? aCurrTuple.getX() : aCurrPoint.getX(),
                            bSnapY ? aCurrTuple.getY() : aCurrPoint.getY(),
                            aCurrPoint.getZ());

                        aRetval.setB3DPoint(a, aSnappedPoint);
                    }

                    // prepare next point
                    if(!bLastRun)
                    {
                        aPrevTuple = aCurrTuple;
                        aCurrPoint = aNextPoint;
                        aCurrTuple = aNextTuple;
                    }
                }

                return aRetval;
            }
            else
            {
                return rCandidate;
            }
        }

// end of namespace

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Messung V0.5
C=90 H=92 G=90

¤ Dauer der Verarbeitung: 0.3 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.