1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_drawinglayer.hxx"
30 
31 #include <drawinglayer/primitive2d/borderlineprimitive2d.hxx>
32 #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
33 #include <basegfx/polygon/b2dpolygon.hxx>
34 #include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
35 #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
36 #include <numeric>
37 
38 //////////////////////////////////////////////////////////////////////////////
39 
40 namespace drawinglayer
41 {
42 	namespace primitive2d
43 	{
44 		Primitive2DSequence BorderLinePrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
45 		{
46 			Primitive2DSequence xRetval;
47 
48 			if(!getStart().equal(getEnd()) && (getCreateInside() || getCreateOutside()))
49 			{
50 				if(isInsideUsed())
51 				{
52 					// get data and vectors
53 					const double fWidth(getWidth());
54 					basegfx::B2DVector aVector(getEnd() - getStart());
55 					aVector.normalize();
56 					const basegfx::B2DVector aPerpendicular(basegfx::getPerpendicular(aVector));
57 
58 					if(isOutsideUsed())
59 					{
60 						// both used, double line definition. Create left and right offset
61 						xRetval.realloc(getCreateInside() && getCreateOutside() ? 2 : 1);
62 						sal_uInt32 nInsert(0);
63 
64 						if(getCreateInside())
65 						{
66 							// create geometry for left
67 							const basegfx::B2DVector aLeftOff(aPerpendicular * (0.5 * (getCorrectedLeftWidth() - fWidth)));
68 							const basegfx::B2DPoint aTmpStart(getStart() + aLeftOff - (getExtendInnerStart() * aVector));
69 							const basegfx::B2DPoint aTmpEnd(getEnd() + aLeftOff + (getExtendInnerEnd() * aVector));
70 							basegfx::B2DPolygon aLeft;
71 
72 							if(leftIsHairline())
73 							{
74 								// create hairline primitive
75 								aLeft.append(aTmpStart);
76 								aLeft.append(aTmpEnd);
77 
78 								xRetval[nInsert++] = Primitive2DReference(new PolygonHairlinePrimitive2D(
79 									aLeft,
80 									getRGBColor()));
81 							}
82 							else
83 							{
84 								// create filled polygon primitive. Already tried to create thick lines
85 								// with the correct LineWidth, but this leads to problems when no AA
86 								// is available and fat line special case reductions between 0.5 < x < 2.5 line widths
87 								// are executed due to the FilledPolygon-do-not-paint-their-bottom-and-right-lines.
88 								const basegfx::B2DVector aLineWidthOffset((getCorrectedLeftWidth() * 0.5) * aPerpendicular);
89 
90 								aLeft.append(aTmpStart + aLineWidthOffset);
91 								aLeft.append(aTmpEnd + aLineWidthOffset);
92 								aLeft.append(aTmpEnd - aLineWidthOffset);
93 								aLeft.append(aTmpStart - aLineWidthOffset);
94 								aLeft.setClosed(true);
95 
96 								xRetval[nInsert++] = Primitive2DReference(new PolyPolygonColorPrimitive2D(
97 									basegfx::B2DPolyPolygon(aLeft), getRGBColor()));
98 							}
99 						}
100 
101 						if(getCreateOutside())
102 						{
103 							// create geometry for right
104 							const basegfx::B2DVector aRightOff(aPerpendicular * (0.5 * (fWidth - getCorrectedRightWidth())));
105 							const basegfx::B2DPoint aTmpStart(getStart() + aRightOff - (getExtendOuterStart() * aVector));
106 							const basegfx::B2DPoint aTmpEnd(getEnd() + aRightOff + (getExtendOuterEnd() * aVector));
107 							basegfx::B2DPolygon aRight;
108 
109 							if(rightIsHairline())
110 							{
111 								// create hairline primitive
112 								aRight.append(aTmpStart);
113 								aRight.append(aTmpEnd);
114 
115 								xRetval[nInsert++] = Primitive2DReference(new PolygonHairlinePrimitive2D(
116 									aRight,
117 									getRGBColor()));
118 							}
119 							else
120 							{
121 								// create filled polygon primitive
122 								const basegfx::B2DVector aLineWidthOffset((getCorrectedRightWidth() * 0.5) * aPerpendicular);
123 
124 								aRight.append(aTmpStart + aLineWidthOffset);
125 								aRight.append(aTmpEnd + aLineWidthOffset);
126 								aRight.append(aTmpEnd - aLineWidthOffset);
127 								aRight.append(aTmpStart - aLineWidthOffset);
128 								aRight.setClosed(true);
129 
130 								xRetval[nInsert++] = Primitive2DReference(new PolyPolygonColorPrimitive2D(
131 									basegfx::B2DPolyPolygon(aRight), getRGBColor()));
132 							}
133 						}
134 					}
135 					else
136 					{
137 						// single line, create geometry
138 						basegfx::B2DPolygon aPolygon;
139 						const double fMaxExtStart(::std::max(getExtendInnerStart(), getExtendOuterStart()));
140 						const double fMaxExtEnd(::std::max(getExtendInnerEnd(), getExtendOuterEnd()));
141 						const basegfx::B2DPoint aTmpStart(getStart() - (fMaxExtStart * aVector));
142 						const basegfx::B2DPoint aTmpEnd(getEnd() + (fMaxExtEnd * aVector));
143 						xRetval.realloc(1);
144 
145 						if(leftIsHairline())
146 						{
147 							// create hairline primitive
148 							aPolygon.append(aTmpStart);
149 							aPolygon.append(aTmpEnd);
150 
151 							xRetval[0] = Primitive2DReference(new PolygonHairlinePrimitive2D(
152 								aPolygon,
153 								getRGBColor()));
154 						}
155 						else
156 						{
157 							// create filled polygon primitive
158 							const basegfx::B2DVector aLineWidthOffset((getCorrectedLeftWidth() * 0.5) * aPerpendicular);
159 
160 							aPolygon.append(aTmpStart + aLineWidthOffset);
161 							aPolygon.append(aTmpEnd + aLineWidthOffset);
162 							aPolygon.append(aTmpEnd - aLineWidthOffset);
163 							aPolygon.append(aTmpStart - aLineWidthOffset);
164 							aPolygon.setClosed(true);
165 
166 							xRetval[0] = Primitive2DReference(new PolyPolygonColorPrimitive2D(
167 								basegfx::B2DPolyPolygon(aPolygon), getRGBColor()));
168 						}
169 					}
170 				}
171 			}
172 
173 			return xRetval;
174 		}
175 
176 		BorderLinePrimitive2D::BorderLinePrimitive2D(
177 			const basegfx::B2DPoint& rStart,
178 			const basegfx::B2DPoint& rEnd,
179 			double fLeftWidth,
180 			double fDistance,
181 			double fRightWidth,
182 			double fExtendInnerStart,
183 			double fExtendInnerEnd,
184 			double fExtendOuterStart,
185 			double fExtendOuterEnd,
186 			bool bCreateInside,
187 			bool bCreateOutside,
188 			const basegfx::BColor& rRGBColor)
189 		:	BufferedDecompositionPrimitive2D(),
190 			maStart(rStart),
191 			maEnd(rEnd),
192 			mfLeftWidth(fLeftWidth),
193 			mfDistance(fDistance),
194 			mfRightWidth(fRightWidth),
195 			mfExtendInnerStart(fExtendInnerStart),
196 			mfExtendInnerEnd(fExtendInnerEnd),
197 			mfExtendOuterStart(fExtendOuterStart),
198 			mfExtendOuterEnd(fExtendOuterEnd),
199 			maRGBColor(rRGBColor),
200 			mbCreateInside(bCreateInside),
201 			mbCreateOutside(bCreateOutside)
202 		{
203 		}
204 
205 		bool BorderLinePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
206 		{
207 			if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
208 			{
209 				const BorderLinePrimitive2D& rCompare = (BorderLinePrimitive2D&)rPrimitive;
210 
211 				return (getStart() == rCompare.getStart()
212 					&& getEnd() == rCompare.getEnd()
213 					&& getLeftWidth() == rCompare.getLeftWidth()
214 					&& getDistance() == rCompare.getDistance()
215 					&& getRightWidth() == rCompare.getRightWidth()
216 					&& getExtendInnerStart() == rCompare.getExtendInnerStart()
217 					&& getExtendInnerEnd() == rCompare.getExtendInnerEnd()
218 					&& getExtendOuterStart() == rCompare.getExtendOuterStart()
219 					&& getExtendOuterEnd() == rCompare.getExtendOuterEnd()
220 					&& getCreateInside() == rCompare.getCreateInside()
221 					&& getCreateOutside() == rCompare.getCreateOutside()
222 					&& getRGBColor() == rCompare.getRGBColor());
223 			}
224 
225 			return false;
226 		}
227 
228 		// provide unique ID
229 		ImplPrimitrive2DIDBlock(BorderLinePrimitive2D, PRIMITIVE2D_ID_BORDERLINEPRIMITIVE2D)
230 
231 	} // end of namespace primitive2d
232 } // end of namespace drawinglayer
233 
234 //////////////////////////////////////////////////////////////////////////////
235 // eof
236