1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
|
#include "Clipping.hxx"
#include "CommonConverters.hxx"
#ifndef _COM_SUN_STAR_DRAWING_POSITION3D_HPP_
#include <com/sun/star/drawing/Position3D.hpp>
#endif
//.............................................................................
namespace chart
{
//.............................................................................
using namespace ::com::sun::star;
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
namespace{
/** @descr This is a supporting function for lcl_clip2d. It computes a new parametric
value for an entering (dTE) or leaving (dTL) intersection point with one
of the edges bounding the clipping area.
For explanation of the parameters please refer to :
Liang-Biarsky parametric line-clipping algorithm as described in:
Computer Graphics: principles and practice, 2nd ed.,
James D. Foley et al.,
Section 3.12.4 on page 117.
*/
bool lcl_CLIPt(double fDenom,double fNum, double & fTE, double & fTL)
{
double fT;
if (fDenom > 0) // Intersection enters: PE
{
fT = fNum / fDenom; // Parametric value at the intersection.
if (fT > fTL) // fTE and fTL crossover
return false; // therefore reject the line.
else if (fT > fTE) // A new fTE has been found.
fTE = fT;
}
else if (fDenom < 0) // Intersection leaves: PL
{
fT = fNum / fDenom; // Parametric Value at the intersection.
if (fT < fTE) // fTE and fTL crossover
return false; // therefore reject the line.
else if (fT < fTL) // A new fTL has been found.
fTL = fT;
}
else if (fNum > 0)
return false; // Line lies on the outside of the edge.
return true;
}
/** @descr The line given by it's two endpoints rP0 and rP1 is clipped at the rectangle
rRectangle. If there is at least a part of it visible then TRUE is returned and
the endpoints of that part are stored in rP0 and rP1. The points rP0 and rP1
may have the same coordinates.
@param rP0 Start point of the line to clip. Modified to contain a start point inside
the clipping area if possible.
@param rP1 End point of the line to clip. Modified to contain an end point inside
the clipping area if possible.
@param rRectangle Clipping area.
@return If the line lies completely or partly inside the clipping area then TRUE
is returned. If the line lies completely outside then FALSE is returned and rP0 and
rP1 are left unmodified.
*/
bool lcl_clip2d(DoublePoint& rPoint0, DoublePoint& rPoint1, const DoubleRectangle& rRectangle)
{
//Direction vector of the line.
DoublePoint aDirection = rPoint1 - rPoint0;
if( aDirection.X==0 && aDirection.Y==0 && rRectangle.isInside(rPoint0) )
{
// Degenerate case of a zero length line.
return true;
}
else
{
// Values of the line parameter where the line enters resp. leaves the rectangle.
double fTE = 0,
fTL = 1;
// Test wether at least a part lies in the four half-planes with respect to
// the rectangles four edges.
if( lcl_CLIPt(aDirection.X, rRectangle.Left - rPoint0.X, fTE, fTL) )
if( lcl_CLIPt(-aDirection.X, rPoint0.X - rRectangle.Right, fTE, fTL) )
if( lcl_CLIPt(aDirection.Y, rRectangle.Top - rPoint0.Y, fTE, fTL) )
if( lcl_CLIPt(-aDirection.Y, rPoint0.Y - rRectangle.Bottom, fTE, fTL) )
{
// At least a part is visible.
if (fTL < 1)
{
// Compute the new end point.
rPoint1.X = rPoint0.X + fTL * aDirection.X;
rPoint1.Y = rPoint0.Y + fTL * aDirection.Y;
}
if (fTE > 0)
{
// Compute the new starting point.
rPoint0.X = rPoint0.X + fTE * aDirection.X;
rPoint0.Y = rPoint0.Y + fTE * aDirection.Y;
}
return true;
}
// Line is not visible.
return false;
}
}
bool lcl_clip2d_(drawing::Position3D& rPoint0, drawing::Position3D& rPoint1, const DoubleRectangle& rRectangle)
{
DoublePoint aP0(rPoint0.PositionX,rPoint0.PositionY);
DoublePoint aP1(rPoint1.PositionX,rPoint1.PositionY);
bool bRet = lcl_clip2d( aP0, aP1, rRectangle );
rPoint0.PositionX = aP0.X;
rPoint0.PositionY = aP0.Y;
rPoint1.PositionX = aP1.X;
rPoint1.PositionY = aP1.Y;
return bRet;
}
}//end anonymous namespace
void Clipping::clipPolygonAtRectangle( const drawing::PolyPolygonShape3D& rPolygon, const DoubleRectangle& rRectangle, drawing::PolyPolygonShape3D& aResult )
{
//rPolygon: XPolygon --> drawing::PolyPolygonShape3D
//aResult: XPolyPolygon --> drawing::PolyPolygonShape3D
aResult.SequenceX.realloc(0);
aResult.SequenceY.realloc(0);
aResult.SequenceZ.realloc(0);
if(!rPolygon.SequenceX.getLength())
return;
drawing::Position3D aFrom;
drawing::Position3D aTo;
sal_Int32 nOldPointCount = rPolygon.SequenceX[0].getLength();
sal_Int32 nNewPoly = -1;
// set last point to a position outside the rectangle, such that the first
// time lcl_clip2d returns true, the comparison to last will always yield false
drawing::Position3D aLast(rRectangle.Left-1.0,rRectangle.Top-1.0, 0.0 );
for(sal_Int32 nOldPoint=1; nOldPoint<nOldPointCount; nOldPoint++)
{
aFrom = getPointFromPoly(rPolygon,nOldPoint-1);
aTo = getPointFromPoly(rPolygon,nOldPoint);
if( lcl_clip2d_(aFrom, aTo, rRectangle) )
{
// compose an XPolygon of as many consecutive points as possible
if(aFrom == aLast)
{
if( !(aTo==aFrom) )
AddPointToPoly( aResult, aTo, nNewPoly );
}
else
{
nNewPoly++;
AddPointToPoly( aResult, aFrom, nNewPoly );
if( !(aTo==aFrom) )
AddPointToPoly( aResult, aTo, nNewPoly );
}
aLast = aTo;
}
}
}
//.............................................................................
} //namespace chart
//.............................................................................
|