/************************************************************************* * * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: implncvt.cxx,v $ * * $Revision: 1.8 $ * * last change: $Author: obo $ $Date: 2006-09-17 12:03:48 $ * * The Contents of this file are made available subject to * the terms of GNU Lesser General Public License Version 2.1. * * * GNU Lesser General Public License Version 2.1 * ============================================= * Copyright 2005 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 * ************************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_vcl.hxx" #ifndef _SV_SALBTYPE_HXX #include "salbtype.hxx" #endif #ifndef _SV_IMPLNCVT_HXX #include "implncvt.hxx" #endif // ----------- // - Defines - // ----------- #define CURVE_LEFT 1 #define CURVE_RIGHT 2 #define CURVE_STRAIGHTON 3 // ----------------- // - ImplFloatPoint // ----------------- struct ImplFloatPoint { double fX; double fY; inline ImplFloatPoint() {} inline ImplFloatPoint( const Point& rPoint ) { fX = rPoint.X(); fY = rPoint.Y(); } inline ImplFloatPoint( double _fX, double _fY ) { fX = _fX; fY = _fY; } inline ImplFloatPoint( const ImplFloatPoint& rPoint ) { fX = rPoint.fX; fY = rPoint.fY; } inline ~ImplFloatPoint() {} void operator+=( const ImplFloatPoint& rPoint ) { fX += rPoint.fX; fY += rPoint.fY; } void operator-=( const ImplFloatPoint& rPoint ) { fX -= rPoint.fX; fY -= rPoint.fY; } void operator*=( const double& rD ) { fX *= rD; fY *= rD; } BOOL operator==( const ImplFloatPoint& rPoint ) const { return ( ( rPoint.fX == fX ) && ( rPoint.fY == fY ) ); } const void operator=( const Point rPoint ) { fX = rPoint.X(); fY = rPoint.Y(); } ImplFloatPoint GetOVec( const ImplFloatPoint& rPoint ) const; ImplFloatPoint GetNVec( const ImplFloatPoint& rPoint ) const; }; // ----------------------------------------------------------------------------- ImplFloatPoint ImplFloatPoint::GetOVec( const ImplFloatPoint& rPoint ) const { double fxt = rPoint.fX - fX; double fyt = rPoint.fY - fY; double fL; if( fyt != 0.0 ) { fyt = -fxt / fyt; fL = sqrt( 1 + fyt * fyt ); return ImplFloatPoint( 1.0 / fL, fyt / fL ); } else return ImplFloatPoint( fyt, ( fxt > 0.0 ) ? 1.0 : -1.0 ); }; // ----------------------------------------------------------------------------- ImplFloatPoint ImplFloatPoint::GetNVec( const ImplFloatPoint& rPoint ) const { const double fxt = rPoint.fX - fX; const double fyt = rPoint.fY - fY; const double fL = hypot( fxt, fyt ); return ImplFloatPoint( fxt / fL, fyt / fL ); }; // -------------------- // - ImplLineConverter // -------------------- ImplLineConverter::ImplLineConverter( const Polygon& rPolygon, const LineInfo& rLineInfo, const Point* pRefPoint ) : mbRefPoint ( FALSE ), mfWidthHalf ( rLineInfo.GetWidth() >> 1 ), maLineInfo ( rLineInfo ), mpFloat0 ( new ImplFloatPoint[ 6 ] ), mpFloat1 ( new ImplFloatPoint[ 6 ] ), mnLines ( 0 ), mpFloatPoint ( NULL ) { UINT16 nIndex, nPolySize = rPolygon.GetSize(); if ( nPolySize ) { if( rPolygon.GetFlags( 0 ) == POLY_NORMAL ) { mpFloatPoint = new ImplFloatPoint[ nPolySize ]; mpFloatPoint[ 0 ] = rPolygon[ 0 ]; nIndex = 0; while( ++nIndex < nPolySize ) // doppelte Punkte eliminieren und ein FloatPointArray anlegen { if( rPolygon.GetFlags( nIndex ) == POLY_NORMAL ) { double nxt = mpFloatPoint[ mnLines ].fX; double nyt = mpFloatPoint[ mnLines ].fY; if ( ( nxt == rPolygon[ nIndex ].X() ) && ( nyt == rPolygon[ nIndex ].Y() ) ) continue; mpFloatPoint[ ++mnLines ] = rPolygon[ nIndex ]; } else { DBG_ERROR( "Bezier points not supported!" ); } } mbClosed = ( mpFloatPoint[ 0 ] == mpFloatPoint[ mnLines ] ) ; if ( ( mnLines == 1 ) && ( maLineInfo.GetStyle() == LINE_DASH ) ) { BOOL bX = mpFloatPoint[ 0 ].fY == mpFloatPoint[ 1 ].fY; BOOL bY = mpFloatPoint[ 0 ].fX == mpFloatPoint[ 1 ].fX; mbRefPoint = pRefPoint && ( bX || bY ); if ( mbRefPoint ) { if ( !maLineInfo.GetDashCount() ) { maLineInfo.SetDashCount( maLineInfo.GetDotCount() ); maLineInfo.SetDashLen( maLineInfo.GetDotLen() ); maLineInfo.SetDotCount( 0 ); } INT32 nDistance = maLineInfo.GetDistance(); INT32 nDashLen = maLineInfo.GetDashCount() * ( maLineInfo.GetDashLen() + nDistance ); INT32 nDotLen = maLineInfo.GetDotCount() * ( maLineInfo.GetDotLen() + nDistance ); if ( bX ) { if ( mpFloatPoint[ 1 ].fX > mpFloatPoint[ 0 ].fX ) { ImplFloatPoint aFloat = mpFloatPoint[ 0 ]; mpFloatPoint[ 0 ] = mpFloatPoint[ 1 ]; mpFloatPoint[ 1 ] = aFloat; } mnRefDistance = (INT32)mpFloatPoint[ mnLines ].fX - pRefPoint->X(); } else { if ( mpFloatPoint[ 1 ].fY > mpFloatPoint[ 0 ].fY ) { ImplFloatPoint aFloat = mpFloatPoint[ 0 ]; mpFloatPoint[ 0 ] = mpFloatPoint[ 1 ]; mpFloatPoint[ 1 ] = aFloat; } mnRefDistance = (INT32)mpFloatPoint[ mnLines ].fY - pRefPoint->Y(); } // mnRefDistance = ( (INT32)mpFloatPoint[ mnLines ].fX - pRefPoint->X() ) + // ( (INT32)mpFloatPoint[ mnLines ].fY - pRefPoint->Y() ); mnRefDistance = mnRefDistance % ( nDashLen + nDotLen ); if ( mnRefDistance < 0 ) mnRefDistance = ( nDashLen + nDotLen ) + mnRefDistance; } } } } }; //------------------------------------------------------------------------ ImplLineConverter::~ImplLineConverter() { delete[] mpFloat0; delete[] mpFloat1; delete[] mpFloatPoint; }; //------------------------------------------------------------------------ const Polygon* ImplLineConverter::ImplGetFirst() { mnFloat1Points = 0; mnLinesAvailable = mnLines; if ( mnLines ) { if ( maLineInfo.GetStyle() == LINE_DASH ) { mnDashCount = maLineInfo.GetDashCount(); mnDotCount = maLineInfo.GetDotCount(); mfDashDotLenght = mnDashCount ? maLineInfo.GetDashLen() : maLineInfo.GetDotLen(); if ( mbRefPoint ) { INT32 nDistance = maLineInfo.GetDistance(); INT32 nDashLen = maLineInfo.GetDashLen() + nDistance; INT32 nDashesLen = maLineInfo.GetDashCount() * nDashLen; INT32 nDotLen = maLineInfo.GetDotLen() + nDistance; if ( mnRefDistance >= nDashesLen ) { // get dotcount if ( nDotLen ) { INT32 nLen = ( mnRefDistance - nDashesLen ) % nDotLen; if ( nLen >= maLineInfo.GetDotLen() ) { mnDotCount -= 1 + ( mnRefDistance - nDashesLen ) / nDotLen; if ( mnDotCount ) mnDashCount = 0; else mnDotCount = maLineInfo.GetDotCount(); mfDashDotLenght = 0.0; mfDistanceLenght = ( maLineInfo.GetDotLen() + nDistance ) - nLen; } else { mnDashCount = 0; mfDashDotLenght = maLineInfo.GetDotLen() - nLen; mnDotCount -= ( mnRefDistance - nDashesLen ) / nDotLen; } } } else { if ( nDashLen ) { // get dashcount INT32 nLen = mnRefDistance % nDashLen; if ( nLen >= maLineInfo.GetDashLen() ) { mfDashDotLenght = 0.0; mfDistanceLenght = ( maLineInfo.GetDashLen() + nDistance ) - nLen; mnDashCount -= 1 + ( mnRefDistance / nDashLen ); } else { mfDashDotLenght = maLineInfo.GetDashLen() - nLen; mnDashCount -= ( mnRefDistance / nDashLen ); } } } if ( ! ( mnDashCount | mnDotCount ) ) { mnDashCount = maLineInfo.GetDashCount(); mnDotCount = maLineInfo.GetDotCount(); } if ( ( mfDashDotLenght == 0.0 ) && ( mfDistanceLenght == 0.0 ) ) mfDistanceLenght = maLineInfo.GetDistance(); } } } return ImplGetNext(); }; //------------------------------------------------------------------------ const Polygon* ImplLineConverter::ImplGetNext() { while( mnFloat1Points || mnLinesAvailable ) { if ( maLineInfo.GetWidth() > 1 ) { if ( !mnFloat1Points ) { ImplFloatPoint aPointA( mpFloatPoint[ mnLinesAvailable-- ] ); ImplFloatPoint aPointB( mpFloatPoint[ mnLinesAvailable ] ); ImplFloatPoint aOVecAB( aPointA.GetOVec( aPointB ) ); ImplFloatPoint aN1Vec( aPointA.GetNVec( aPointB ) ); aN1Vec *= mfWidthHalf; if ( !mbClosed && ( ( mnLinesAvailable + 1 ) == mnLines ) ) aPointA -= aN1Vec; aOVecAB *= mfWidthHalf; mpFloat0[ 0 ] = aPointA; mpFloat0[ 0 ] -= aOVecAB; mpFloat0[ 3 ] = aPointA; mpFloat0[ 3 ] += aOVecAB; mpFloat0[ 1 ] = aPointB; mpFloat0[ 1 ] -= aOVecAB; mpFloat0[ 2 ] = aPointB; mpFloat0[ 2 ] += aOVecAB; double f1D = ( aN1Vec.fX == 0 ) ? 1 : ( aN1Vec.fY / aN1Vec.fX ); double f2D = -f1D; mnFloat0Points = 4; int nDirection; BOOL bContinues = ( mnLinesAvailable || mbClosed ); if ( bContinues ) { ImplFloatPoint aPointC; if ( mnLinesAvailable ) aPointC = mpFloatPoint[ mnLinesAvailable - 1 ]; else aPointC = mpFloatPoint[ mnLines - 1 ]; ImplFloatPoint aOVecBC( aPointB.GetOVec( aPointC ) ); aOVecBC *= mfWidthHalf; ImplFloatPoint aPointR0( aPointB ); aPointR0 -= aOVecBC; ImplFloatPoint aPointR1( aPointB ); aPointR1 += aOVecBC; ImplFloatPoint aN2Vec( aPointB.GetNVec( aPointC ) ); aN2Vec *= mfWidthHalf; f2D = ( fabs( aN2Vec.fX ) < 0.00000001 ) ? 1 : ( aN2Vec.fY / aN2Vec.fX ); if ( fabs( f1D - f2D ) < 0.00000001 ) nDirection = CURVE_STRAIGHTON; else { if ( ( aN1Vec.fX * aN2Vec.fY - aN1Vec.fY * aN2Vec.fX ) > 0 ) nDirection = CURVE_LEFT; else nDirection = CURVE_RIGHT; } if ( nDirection != CURVE_STRAIGHTON ) { double fWidth; ImplFloatPoint aDestPoint; if ( hypot( aPointR0.fX - aPointA.fX, aPointR0.fY - aPointA.fY ) > hypot( aPointR1.fX - aPointA.fX, aPointR1.fY - aPointA.fY ) ) aDestPoint = aPointR0; else aDestPoint = aPointR1; UINT16 nFirst = 0; if ( aN1Vec.fY > 0 ) { if ( nDirection != CURVE_RIGHT ) nFirst++; } else { if ( nDirection == CURVE_RIGHT ) nFirst++; } fWidth = hypot( mpFloat0[ 1 + nFirst ].fX - aDestPoint.fX, mpFloat0[ 1 + nFirst ].fY - aDestPoint.fY ); fWidth = sqrt( fWidth * fWidth / 2 ); if ( fWidth > mfWidthHalf ) { // Spitzer Winkel : mnFloat0Points = 6; mpFloat0[ 4 + nFirst ^ 1 ] = aDestPoint; aDestPoint -= aN2Vec; mpFloat0[ 4 + nFirst ] = aDestPoint; mpFloat0[ 1 + nFirst ] += aN1Vec; } else { // Stumpferwinkel : Schnittpunkt wird berechnet mnFloat0Points = 5; ImplFloatPoint aSourcePoint; double fX = 0; double fY; double fBDest = 0; double fBSource = 0; aSourcePoint = mpFloat0[ 1 + nFirst ]; int nValid = 0; if ( fabs( aN2Vec.fX ) < 0.00000001 ) { fX = aDestPoint.fX; nValid = 1; } else fBDest = aDestPoint.fY - ( aN2Vec.fY / aN2Vec.fX * aDestPoint.fX ); if ( fabs( aN1Vec.fX ) < 0.000000001 ) { fX = aSourcePoint.fX; nValid = 2; } else fBSource = aSourcePoint.fY - ( aN1Vec.fY / aN1Vec.fX * aSourcePoint.fX ); if ( !nValid ) fX = ( fBSource - fBDest ) / ( aN2Vec.fY / aN2Vec.fX - aN1Vec.fY / aN1Vec.fX ); if ( nValid < 2 ) fY = aN1Vec.fY / aN1Vec.fX * fX + fBSource; else fY = aN2Vec.fY / aN2Vec.fX * fX + fBDest; mpFloat0[ 1 + nFirst ].fX = fX; mpFloat0[ 1 + nFirst ].fY = fY; mpFloat0[ 4 ] = aDestPoint; } } else if ( ( aN1Vec.fX - aN2Vec.fX + aN1Vec.fY - aN2Vec.fY ) != 0 ) // besitzt zweiter Richtungsvektor die gleiche Steigung aber andere bContinues = FALSE; // Richtung, dann wird hinten noch eine halbe Linienbreite angehaengt } if ( !bContinues ) { mpFloat0[ 1 ] += aN1Vec; mpFloat0[ 2 ] += aN1Vec; } } else { mnFloat0Points = mnFloat1Points; ImplFloatPoint* pTemp = mpFloat1; mpFloat1 = mpFloat0; mpFloat0 = pTemp; } if ( maLineInfo.GetStyle() == LINE_DASH ) { double fLenghtDone = 0; double fLenght = ( mfDashDotLenght > 0.0 ) ? mfDashDotLenght : mfDistanceLenght; double fDistance; fDistance = hypot( mpFloat0[ 0 ].fX - mpFloat0[ 1 ].fX, mpFloat0[ 0 ].fY - mpFloat0[ 1 ].fY ); if ( mnFloat0Points == 5 ) { double fDist = hypot( mpFloat0[ 2 ].fX - mpFloat0[ 3 ].fX, mpFloat0[ 2 ].fY - mpFloat0[ 3 ].fY ); if ( fDist < fDistance ) fDistance = fDist; } if ( fDistance > fLenght ) { fLenghtDone = fLenght; ImplFloatPoint aNVec( mpFloat0[ 0 ].GetNVec( mpFloat0[ 1 ] ) ); aNVec *= fLenght; mnFloat1Points = mnFloat0Points; ImplFloatPoint* pTemp = mpFloat1; mpFloat1 = mpFloat0; mpFloat0 = pTemp; mnFloat0Points = 4; mpFloat0[ 0 ] = mpFloat0[ 1 ] = mpFloat1[ 0 ]; mpFloat0[ 1 ] += aNVec; mpFloat0[ 2 ] = mpFloat0[ 3 ] = mpFloat1[ 3 ]; mpFloat0[ 2 ] += aNVec; mpFloat1[ 0 ] = mpFloat0[ 1 ]; mpFloat1[ 3 ] = mpFloat0[ 2 ]; } else { mnFloat1Points = 0; fLenghtDone = fDistance; } if ( mfDashDotLenght > 0.0 ) { // Ein Dash oder Dot wurde erzeugt mfDashDotLenght -= fLenghtDone; if ( mfDashDotLenght == 0.0 ) { // Komplett erzeugt if ( mnDashCount ) mnDashCount--; else mnDotCount--; if ( ! ( mnDashCount | mnDotCount ) ) { mnDashCount = maLineInfo.GetDashCount(); mnDotCount = maLineInfo.GetDotCount(); } mfDistanceLenght = maLineInfo.GetDistance(); } } else { // Das erzeugte Polygon muessen wir ignorieren mfDistanceLenght -= fLenghtDone; if ( mfDistanceLenght == 0.0 ) mfDashDotLenght = ( mnDashCount ) ? maLineInfo.GetDashLen() : maLineInfo.GetDotLen(); continue; } } maPolygon.SetSize( (UINT16)mnFloat0Points ); UINT16 i = 0; maPolygon[ i++ ] = Point( FRound( mpFloat0[ 0 ].fX ), FRound( mpFloat0[ 0 ].fY ) ); maPolygon[ i++ ] = Point( FRound( mpFloat0[ 1 ].fX ), FRound( mpFloat0[ 1 ].fY ) ); if ( mnFloat0Points > 4 ) maPolygon[ i++ ] = Point( FRound( mpFloat0[ 4 ].fX ), FRound( mpFloat0[ 4 ].fY ) ); if ( mnFloat0Points > 5 ) maPolygon[ i++ ] = Point( FRound( mpFloat0[ 5 ].fX ), FRound( mpFloat0[ 5 ].fY ) ); maPolygon[ i++ ] = Point( FRound( mpFloat0[ 2 ].fX ), FRound( mpFloat0[ 2 ].fY ) ); maPolygon[ i ] = Point( FRound( mpFloat0[ 3 ].fX ), FRound( mpFloat0[ 3 ].fY ) ); } else { if ( !mnFloat1Points ) { mpFloat0[ 0 ] = mpFloatPoint[ mnLinesAvailable-- ]; mpFloat0[ 1 ] = mpFloatPoint[ mnLinesAvailable ]; } else { mpFloat0[ 0 ] = mpFloat1[ 0 ]; mpFloat0[ 1 ] = mpFloat1[ 1 ]; } if ( maLineInfo.GetStyle() == LINE_DASH ) { double fLenghtDone = 0; double fLenght = ( mfDashDotLenght > 0.0 ) ? mfDashDotLenght : mfDistanceLenght; double fDistance; fDistance = hypot( mpFloat0[ 0 ].fX - mpFloat0[ 1 ].fX, mpFloat0[ 0 ].fY - mpFloat0[ 1 ].fY ); if ( fDistance > fLenght ) { fLenghtDone = fLenght; ImplFloatPoint aNVec( mpFloat0[ 0 ].GetNVec( mpFloat0[ 1 ] ) ); aNVec *= fLenght; mpFloat1[ 1 ] = mpFloat0[ 1 ]; mpFloat0[ 1 ] = mpFloat0[ 0 ]; mpFloat0[ 1 ] += aNVec; mpFloat1[ 0 ] = mpFloat0[ 1 ]; mnFloat1Points = 2; } else { mnFloat1Points = 0; fLenghtDone = fDistance; } if ( mfDashDotLenght > 0.0 ) { // Ein Dash oder Dot wurde erzeugt mfDashDotLenght -= fLenghtDone; if ( mfDashDotLenght == 0.0 ) { // Komplett erzeugt if ( mnDashCount ) mnDashCount--; else mnDotCount--; if ( ! ( mnDashCount | mnDotCount ) ) { mnDashCount = maLineInfo.GetDashCount(); mnDotCount = maLineInfo.GetDotCount(); } mfDistanceLenght = maLineInfo.GetDistance(); } } else { // Das erzeugte Polygon muessen wir ignorieren mfDistanceLenght -= fLenghtDone; if ( mfDistanceLenght == 0.0 ) mfDashDotLenght = ( mnDashCount ) ? maLineInfo.GetDashLen() : maLineInfo.GetDotLen(); continue; } } maPolygon.SetSize( 2 ); maPolygon[ 0 ] = Point( (long)mpFloat0[ 0 ].fX, (long)mpFloat0[ 0 ].fY ); maPolygon[ 1 ] = Point( (long)mpFloat0[ 1 ].fX, (long)mpFloat0[ 1 ].fY ); } return &maPolygon; } return NULL; };