/************************************************************************* * * $RCSfile: svdtouch.cxx,v $ * * $Revision: 1.1.1.1 $ * * last change: $Author: hr $ $Date: 2000-09-18 17:01:26 $ * * 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): _______________________________________ * * ************************************************************************/ #include "svdtouch.hxx" #include "xoutx.hxx" #ifndef _BIGINT_HXX //autogen #include <tools/bigint.hxx> #endif #ifndef _SV_POLY_HXX //autogen #include <vcl/poly.hxx> #endif //////////////////////////////////////////////////////////////////////////////////////////////////// class ImpPolyHitCalc { public: long x1,x2,y1,y2; // Koordinaten des Rect, muessen sortiert sein! FASTBOOL bEdge; // ein Punkt lag genau auf einer Kante FASTBOOL bIntersect; // mind. 2 Punkte auf verschiedenen Seiten einer Kante FASTBOOL bPntInRect; // mind. 1 Punkt war vollstaendig im Rect USHORT nOCnt; // wenn Counter ungerade, dann getroffen USHORT nUCnt; // wenn Counter ungerade, dann getroffen USHORT nLCnt; // wenn Counter ungerade, dann getroffen USHORT nRCnt; // wenn Counter ungerade, dann getroffen FASTBOOL bLine; // TRUE=PolyLine, kein Polygon public: ImpPolyHitCalc(const Rectangle& aR, FASTBOOL bIsLine=FALSE) { bLine=bIsLine; bEdge=FALSE; bIntersect=FALSE; bPntInRect=FALSE; x1=aR.Left(); x2=aR.Right(); y1=aR.Top(); y2=aR.Bottom(); nOCnt=0; nUCnt=0; nLCnt=0; nRCnt=0; } FASTBOOL IsDecided() { return bEdge || bIntersect || bPntInRect; } void CheckPntInRect(const Point& rP) { if (!bPntInRect) { bPntInRect=rP.X()>=x1 && rP.X()<=x2 && rP.Y()>=y1 && rP.Y()<=y2; } } FASTBOOL IsHit() { return (!bLine && (nOCnt & 1)==1) || IsDecided(); } }; #define CAREFUL_MULDIV(Res,Val,Mul,Div) { \ if (Abs(Val)>0xB504 || Abs(Mul)>0xB504) { \ BigInt aBigTemp(Val); \ aBigTemp*=Mul; \ aBigTemp/=Div; \ Res=long(aBigTemp); \ } else { \ Res=Val*Mul/Div; \ } \ } void ImpCheckIt(ImpPolyHitCalc& rH, long lx1, long ly1, long lx2, long ly2, long rx1, long ry1, long rx2, long ry2, USHORT& nOCnt, USHORT& nUCnt) { if ((ly1>ly2) || ((ly1==ly2) && (lx1>lx2))) { long nTmp; // die 2 Punkte nach Y sortieren nTmp=lx1; lx1=lx2; lx2=nTmp; nTmp=ly1; ly1=ly2; ly2=nTmp; } FASTBOOL b1=FALSE,b2=FALSE,b3=FALSE,b4=FALSE; // je 1 Flag fuer jeden der 4 Punkte LO,RO,LU,RU FASTBOOL bx1,bx2; FASTBOOL by1=ly1<=ry1 && ly2>ry1; FASTBOOL by2=ly1<=ry2 && ly2>ry2; long dx,dy,a; if (by1 || by2) { dx=lx2-lx1; dy=ly2-ly1; } if (by1) { // Nur wer die Scanline schneidet bx1=lx1<rx1; // x1,y1 bx2=lx2<rx1; FASTBOOL bA=FALSE; // Optimierung: ggf eine Division sparen if (bx1 && bx2) b1=TRUE; else if (bx1 || bx2) { long yTemp=ry1-ly1; CAREFUL_MULDIV(a,dx,yTemp,dy); // a=dx*yTemp/dy; a+=lx1; bA=TRUE; rH.bEdge=(a==rx1); if (a<rx1) b1=TRUE; } // x2,y1 bx1=lx1<rx2; bx2=lx2<rx2; if (bx1 && bx2) b2=TRUE; else if (bx1 || bx2) { if (!bA) { long yTemp=ry1-ly1; CAREFUL_MULDIV(a,dx,yTemp,dy); a+=lx1; } rH.bEdge=(a==rx2); if (a<rx2) b2=TRUE; } } if (by2) { // Nur wer die Scanline schneidet bx1=lx1<rx1; // x1,y2 bx2=lx2<rx1; FASTBOOL bA=FALSE; // Optimierung: ggf eine Division sparen if (bx1 && bx2) b3=TRUE; else if (bx1 || bx2) { long yTemp=ry2-ly1; CAREFUL_MULDIV(a,dx,yTemp,dy); a+=lx1; bA=TRUE; rH.bEdge=(a==rx1); if (a<rx1) b3=TRUE; } bx1=lx1<rx2; // x2,y2 bx2=lx2<rx2; if (bx1 && bx2) b4=TRUE; else if (bx1 || bx2) { if (!bA) { long yTemp=ry2-ly1; CAREFUL_MULDIV(a,dx,yTemp,dy); a+=lx1; } rH.bEdge=(a==rx2); if (a<rx2) b4=TRUE; } } if (by1 || by2) { // nun die Ergebnisse auswerten if (by1 && by2) { // Linie durch beide Scanlines if (b1 && b2 && b3 && b4) { nOCnt++; nUCnt++; } // Rect komplett rechts neben der Linie else if (b1 || b2 || b3 || b4) rH.bIntersect=TRUE; // Nur zum Teil->Schnittpunkt } else { // ansonsten Ober- und Unterkante des Rects getrennt betrachten if (by1) { // Linie durch Oberkante if (b1 && b2) nOCnt++; // Oberkante komplett rechts neben der Linie else if (b1 || b2) rH.bIntersect=TRUE; // Nur zum Teil->Schnittpunkt } if (by2) { // Linie durch Unterkante if (b3 && b4) nUCnt++; // Unterkante komplett rechts neben der Linie else if (b3 || b4) rH.bIntersect=TRUE; // Nur zum Teil->Schnittpunkt } } } } void CheckPolyHit(const Polygon& rPoly, ImpPolyHitCalc& rH) { USHORT nAnz=rPoly.GetSize(); if (nAnz==0) return; if (nAnz==1) { rH.CheckPntInRect(rPoly[0]); return; } Point aPt0=rPoly[USHORT(nAnz-1)]; rH.CheckPntInRect(aPt0); USHORT i=0; if (rH.bLine) { aPt0=rPoly[0]; i++; } for (; i<nAnz && !rH.IsDecided(); i++) { Point aP1(aPt0); Point aP2(rPoly[i]); rH.CheckPntInRect(aP2); if (!rH.IsDecided()) { ImpCheckIt(rH,aP1.X(),aP1.Y(),aP2.X(),aP2.Y(),rH.x1,rH.y1,rH.x2,rH.y2,rH.nOCnt,rH.nUCnt); ImpCheckIt(rH,aP1.Y(),aP1.X(),aP2.Y(),aP2.X(),rH.y1,rH.x1,rH.y2,rH.x2,rH.nLCnt,rH.nRCnt); } aPt0=rPoly[i]; } if (!rH.bLine) { // Sicherheitshalber nochmal checken if ((rH.nOCnt&1)!=(rH.nUCnt&1)) rH.bIntersect=TRUE; // da wird wohl eine durchgegangen sein if ((rH.nLCnt&1)!=(rH.nRCnt&1)) rH.bIntersect=TRUE; // da wird wohl eine durchgegangen sein if ((rH.nOCnt&1)!=(rH.nLCnt&1)) rH.bIntersect=TRUE; // da wird wohl eine durchgegangen sein } } FASTBOOL IsRectTouchesPoly(const Polygon& rPoly, const Rectangle& rHit) { ImpPolyHitCalc aHit(rHit); CheckPolyHit(rPoly,aHit); return aHit.IsHit(); } FASTBOOL IsRectTouchesPoly(const PolyPolygon& rPoly, const Rectangle& rHit) { ImpPolyHitCalc aHit(rHit); USHORT nAnz=rPoly.Count(); for (USHORT i=0; i<nAnz && !aHit.IsDecided(); i++) { CheckPolyHit(rPoly.GetObject(i),aHit); } return aHit.IsHit(); } FASTBOOL IsRectTouchesPoly(const XPolygon& rPoly, const Rectangle& rHit, OutputDevice* pOut) { return IsRectTouchesPoly(XOutCreatePolygon(rPoly,pOut),rHit); } FASTBOOL IsRectTouchesPoly(const XPolyPolygon& rPoly, const Rectangle& rHit, OutputDevice* pOut) { ImpPolyHitCalc aHit(rHit); USHORT nAnz=rPoly.Count(); for (USHORT i=0; i<nAnz && !aHit.IsDecided(); i++) { CheckPolyHit(XOutCreatePolygon(rPoly[i],pOut),aHit); } return aHit.IsHit(); } FASTBOOL IsRectTouchesLine(const Point& rPt1, const Point& rPt2, const Rectangle& rHit) { Polygon aPol(2); aPol[0]=rPt1; aPol[1]=rPt2; ImpPolyHitCalc aHit(rHit,TRUE); CheckPolyHit(aPol,aHit); return aHit.IsHit(); } FASTBOOL IsRectTouchesLine(const Polygon& rLine, const Rectangle& rHit) { ImpPolyHitCalc aHit(rHit,TRUE); CheckPolyHit(rLine,aHit); return aHit.IsHit(); } FASTBOOL IsRectTouchesLine(const PolyPolygon& rLine, const Rectangle& rHit) { ImpPolyHitCalc aHit(rHit,TRUE); USHORT nAnz=rLine.Count(); for (USHORT nNum=0; nNum<nAnz && !aHit.IsHit(); nNum++) { CheckPolyHit(rLine[nNum],aHit); } return aHit.IsHit(); } FASTBOOL IsRectTouchesLine(const XPolygon& rLine, const Rectangle& rHit, OutputDevice* pOut) { return IsRectTouchesLine(XOutCreatePolygon(rLine,pOut),rHit); } FASTBOOL IsRectTouchesLine(const XPolyPolygon& rLine, const Rectangle& rHit, OutputDevice* pOut) { ImpPolyHitCalc aHit(rHit,TRUE); USHORT nAnz=rLine.Count(); for (USHORT nNum=0; nNum<nAnz && !aHit.IsHit(); nNum++) { CheckPolyHit(XOutCreatePolygon(rLine[nNum],pOut),aHit); } return aHit.IsHit(); } BYTE CheckPointTouchesPoly(const Polygon& rPoly, const Point& rHit) // 0=Ausserhalb, 1=Innerhalb, 2=Beruehrung { USHORT nAnz=rPoly.GetSize(); if (nAnz<2) return FALSE; FASTBOOL bEdge=FALSE; USHORT nCnt=0; Point aPt0=rPoly[USHORT(nAnz-1)]; for (USHORT i=0; i<nAnz && !bEdge; i++) { Point aP1(rPoly[i]); Point aP2(aPt0); if ((aP1.Y()>aP2.Y()) || ((aP1.Y()==aP2.Y()) && (aP1.X()>aP2.X()))) { Point aTmp(aP1); aP1=aP2; aP2=aTmp; } bEdge=((aP1.X()==aP2.X()) && (rHit.X()==aP1.X()) && (rHit.Y()>=aP1.Y()) && (rHit.Y()<=aP2.Y())) || ((aP1.Y()==aP2.Y()) && (rHit.Y()==aP1.Y()) && (rHit.X()>=aP1.X()) && (rHit.X()<=aP2.X())) || (rHit.X()==aP1.X()) && (rHit.Y()==aP1.Y()); if (!bEdge && aP1.Y()<=rHit.Y() && aP2.Y()>rHit.Y()) { // Nur wer die Scanline schneidet FASTBOOL bx1=aP1.X()<rHit.X(); FASTBOOL bx2=aP2.X()<rHit.X(); if (bx1 && bx2) nCnt++; else if (bx1 || bx2) { long dx=aP2.X()-aP1.X(); long dy=aP2.Y()-aP1.Y(); long yTemp=rHit.Y()-aP1.Y(); long xTemp; if (Abs(dx)>0xB504 || Abs(yTemp)>0xB504) { // gegen Integerueberlaeufe BigInt aBigTemp(dx); aBigTemp*=yTemp; aBigTemp/=dy; xTemp=long(aBigTemp); } else { xTemp=dx*yTemp /dy; } xTemp+=aP1.X(); bEdge=(xTemp==rHit.X()); if (xTemp<rHit.X()) nCnt++; } } aPt0=rPoly[i]; } if (bEdge) return 2; return (nCnt & 1)==1; } FASTBOOL IsPointInsidePoly(const Polygon& rPoly, const Point& rHit) { return CheckPointTouchesPoly(rPoly,rHit)!=0; } FASTBOOL IsPointInsidePoly(const PolyPolygon& rPoly, const Point& rHit) { FASTBOOL bInside=FALSE; FASTBOOL bEdge=FALSE; USHORT nAnz=rPoly.Count(); for (USHORT i=0; i<nAnz && !bEdge; i++) { BYTE n=CheckPointTouchesPoly(rPoly.GetObject(i),rHit); bEdge=n==2; if (n==1) bInside=!bInside; } return bInside || bEdge; } FASTBOOL IsPointInsidePoly(const XPolygon& rPoly, const Point& rHit, OutputDevice* pOut) { return IsPointInsidePoly(XOutCreatePolygon(rPoly,pOut),rHit); } FASTBOOL IsPointInsidePoly(const XPolyPolygon& rPoly, const Point& rHit, OutputDevice* pOut) { FASTBOOL bInside=FALSE; FASTBOOL bEdge=FALSE; USHORT nAnz=rPoly.Count(); for (USHORT i=0; i<nAnz && !bEdge; i++) { BYTE n=CheckPointTouchesPoly(XOutCreatePolygon(rPoly[i],pOut),rHit); bEdge=n==2; if (n==1) bInside=!bInside; } return bInside || bEdge; } ////////////////////////////////////////////////////////////////////////////////////////////////////