1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_drawinglayer.hxx"
26 
27 #include <drawinglayer/primitive2d/borderlineprimitive2d.hxx>
28 #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
29 #include <basegfx/polygon/b2dpolygon.hxx>
30 #include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
31 #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
32 #include <numeric>
33 
34 //////////////////////////////////////////////////////////////////////////////
35 
36 namespace drawinglayer
37 {
38 	namespace primitive2d
39 	{
create2DDecomposition(const geometry::ViewInformation2D &) const40 		Primitive2DSequence BorderLinePrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
41 		{
42 			Primitive2DSequence xRetval;
43 
44 			if(!getStart().equal(getEnd()) && (getCreateInside() || getCreateOutside()))
45 			{
46 				if(isInsideUsed())
47 				{
48 					// get data and vectors
49 					const double fWidth(getWidth());
50 					basegfx::B2DVector aVector(getEnd() - getStart());
51 					aVector.normalize();
52 					const basegfx::B2DVector aPerpendicular(basegfx::getPerpendicular(aVector));
53 
54 					if(isOutsideUsed())
55 					{
56 						// both used, double line definition. Create left and right offset
57 						xRetval.realloc(getCreateInside() && getCreateOutside() ? 2 : 1);
58 						sal_uInt32 nInsert(0);
59 
60 						if(getCreateInside())
61 						{
62 							// create geometry for left
63 							const basegfx::B2DVector aLeftOff(aPerpendicular * (0.5 * (getCorrectedLeftWidth() - fWidth)));
64 							const basegfx::B2DPoint aTmpStart(getStart() + aLeftOff - (getExtendInnerStart() * aVector));
65 							const basegfx::B2DPoint aTmpEnd(getEnd() + aLeftOff + (getExtendInnerEnd() * aVector));
66 							basegfx::B2DPolygon aLeft;
67 
68 							if(leftIsHairline())
69 							{
70 								// create hairline primitive
71 								aLeft.append(aTmpStart);
72 								aLeft.append(aTmpEnd);
73 
74 								xRetval[nInsert++] = Primitive2DReference(new PolygonHairlinePrimitive2D(
75 									aLeft,
76 									getRGBColor()));
77 							}
78 							else
79 							{
80 								// create filled polygon primitive. Already tried to create thick lines
81 								// with the correct LineWidth, but this leads to problems when no AA
82 								// is available and fat line special case reductions between 0.5 < x < 2.5 line widths
83 								// are executed due to the FilledPolygon-do-not-paint-their-bottom-and-right-lines.
84 								const basegfx::B2DVector aLineWidthOffset((getCorrectedLeftWidth() * 0.5) * aPerpendicular);
85 
86 								aLeft.append(aTmpStart + aLineWidthOffset);
87 								aLeft.append(aTmpEnd + aLineWidthOffset);
88 								aLeft.append(aTmpEnd - aLineWidthOffset);
89 								aLeft.append(aTmpStart - aLineWidthOffset);
90 								aLeft.setClosed(true);
91 
92 								xRetval[nInsert++] = Primitive2DReference(new PolyPolygonColorPrimitive2D(
93 									basegfx::B2DPolyPolygon(aLeft), getRGBColor()));
94 							}
95 						}
96 
97 						if(getCreateOutside())
98 						{
99 							// create geometry for right
100 							const basegfx::B2DVector aRightOff(aPerpendicular * (0.5 * (fWidth - getCorrectedRightWidth())));
101 							const basegfx::B2DPoint aTmpStart(getStart() + aRightOff - (getExtendOuterStart() * aVector));
102 							const basegfx::B2DPoint aTmpEnd(getEnd() + aRightOff + (getExtendOuterEnd() * aVector));
103 							basegfx::B2DPolygon aRight;
104 
105 							if(rightIsHairline())
106 							{
107 								// create hairline primitive
108 								aRight.append(aTmpStart);
109 								aRight.append(aTmpEnd);
110 
111 								xRetval[nInsert++] = Primitive2DReference(new PolygonHairlinePrimitive2D(
112 									aRight,
113 									getRGBColor()));
114 							}
115 							else
116 							{
117 								// create filled polygon primitive
118 								const basegfx::B2DVector aLineWidthOffset((getCorrectedRightWidth() * 0.5) * aPerpendicular);
119 
120 								aRight.append(aTmpStart + aLineWidthOffset);
121 								aRight.append(aTmpEnd + aLineWidthOffset);
122 								aRight.append(aTmpEnd - aLineWidthOffset);
123 								aRight.append(aTmpStart - aLineWidthOffset);
124 								aRight.setClosed(true);
125 
126 								xRetval[nInsert++] = Primitive2DReference(new PolyPolygonColorPrimitive2D(
127 									basegfx::B2DPolyPolygon(aRight), getRGBColor()));
128 							}
129 						}
130 					}
131 					else
132 					{
133 						// single line, create geometry
134 						basegfx::B2DPolygon aPolygon;
135 						const double fMaxExtStart(::std::max(getExtendInnerStart(), getExtendOuterStart()));
136 						const double fMaxExtEnd(::std::max(getExtendInnerEnd(), getExtendOuterEnd()));
137 						const basegfx::B2DPoint aTmpStart(getStart() - (fMaxExtStart * aVector));
138 						const basegfx::B2DPoint aTmpEnd(getEnd() + (fMaxExtEnd * aVector));
139 						xRetval.realloc(1);
140 
141 						if(leftIsHairline())
142 						{
143 							// create hairline primitive
144 							aPolygon.append(aTmpStart);
145 							aPolygon.append(aTmpEnd);
146 
147 							xRetval[0] = Primitive2DReference(new PolygonHairlinePrimitive2D(
148 								aPolygon,
149 								getRGBColor()));
150 						}
151 						else
152 						{
153 							// create filled polygon primitive
154 							const basegfx::B2DVector aLineWidthOffset((getCorrectedLeftWidth() * 0.5) * aPerpendicular);
155 
156 							aPolygon.append(aTmpStart + aLineWidthOffset);
157 							aPolygon.append(aTmpEnd + aLineWidthOffset);
158 							aPolygon.append(aTmpEnd - aLineWidthOffset);
159 							aPolygon.append(aTmpStart - aLineWidthOffset);
160 							aPolygon.setClosed(true);
161 
162 							xRetval[0] = Primitive2DReference(new PolyPolygonColorPrimitive2D(
163 								basegfx::B2DPolyPolygon(aPolygon), getRGBColor()));
164 						}
165 					}
166 				}
167 			}
168 
169 			return xRetval;
170 		}
171 
BorderLinePrimitive2D(const basegfx::B2DPoint & rStart,const basegfx::B2DPoint & rEnd,double fLeftWidth,double fDistance,double fRightWidth,double fExtendInnerStart,double fExtendInnerEnd,double fExtendOuterStart,double fExtendOuterEnd,bool bCreateInside,bool bCreateOutside,const basegfx::BColor & rRGBColor)172 		BorderLinePrimitive2D::BorderLinePrimitive2D(
173 			const basegfx::B2DPoint& rStart,
174 			const basegfx::B2DPoint& rEnd,
175 			double fLeftWidth,
176 			double fDistance,
177 			double fRightWidth,
178 			double fExtendInnerStart,
179 			double fExtendInnerEnd,
180 			double fExtendOuterStart,
181 			double fExtendOuterEnd,
182 			bool bCreateInside,
183 			bool bCreateOutside,
184 			const basegfx::BColor& rRGBColor)
185 		:	BufferedDecompositionPrimitive2D(),
186 			maStart(rStart),
187 			maEnd(rEnd),
188 			mfLeftWidth(fLeftWidth),
189 			mfDistance(fDistance),
190 			mfRightWidth(fRightWidth),
191 			mfExtendInnerStart(fExtendInnerStart),
192 			mfExtendInnerEnd(fExtendInnerEnd),
193 			mfExtendOuterStart(fExtendOuterStart),
194 			mfExtendOuterEnd(fExtendOuterEnd),
195 			maRGBColor(rRGBColor),
196 			mbCreateInside(bCreateInside),
197 			mbCreateOutside(bCreateOutside)
198 		{
199 		}
200 
operator ==(const BasePrimitive2D & rPrimitive) const201 		bool BorderLinePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
202 		{
203 			if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
204 			{
205 				const BorderLinePrimitive2D& rCompare = (BorderLinePrimitive2D&)rPrimitive;
206 
207 				return (getStart() == rCompare.getStart()
208 					&& getEnd() == rCompare.getEnd()
209 					&& getLeftWidth() == rCompare.getLeftWidth()
210 					&& getDistance() == rCompare.getDistance()
211 					&& getRightWidth() == rCompare.getRightWidth()
212 					&& getExtendInnerStart() == rCompare.getExtendInnerStart()
213 					&& getExtendInnerEnd() == rCompare.getExtendInnerEnd()
214 					&& getExtendOuterStart() == rCompare.getExtendOuterStart()
215 					&& getExtendOuterEnd() == rCompare.getExtendOuterEnd()
216 					&& getCreateInside() == rCompare.getCreateInside()
217 					&& getCreateOutside() == rCompare.getCreateOutside()
218 					&& getRGBColor() == rCompare.getRGBColor());
219 			}
220 
221 			return false;
222 		}
223 
224 		// provide unique ID
225 		ImplPrimitrive2DIDBlock(BorderLinePrimitive2D, PRIMITIVE2D_ID_BORDERLINEPRIMITIVE2D)
226 
227 	} // end of namespace primitive2d
228 } // end of namespace drawinglayer
229 
230 //////////////////////////////////////////////////////////////////////////////
231 // eof
232