cropprimitive2d.cxx (2376739d) cropprimitive2d.cxx (c0d661f1)
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

--- 65 unchanged lines hidden (view full) ---

74 }
75
76 Primitive2DSequence CropPrimitive2D::get2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
77 {
78 Primitive2DSequence xRetval;
79
80 if(getChildren().hasElements())
81 {
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

--- 65 unchanged lines hidden (view full) ---

74 }
75
76 Primitive2DSequence CropPrimitive2D::get2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
77 {
78 Primitive2DSequence xRetval;
79
80 if(getChildren().hasElements())
81 {
82 // decompose to have current translate and scale
83 basegfx::B2DVector aScale, aTranslate;
84 double fRotate, fShearX;
82 // get original object scale in unit coordinates (no mirroring)
83 const basegfx::B2DVector aObjectScale(basegfx::absolute(getTransformation() * basegfx::B2DVector(1.0, 1.0)));
85
84
86 getTransformation().decompose(aScale, aTranslate, fRotate, fShearX);
87
88 // detect 180 degree rotation, this is the same as mirrored in X and Y,
89 // thus change to mirroring. Prefer mirroring here. Use the equal call
90 // with getSmallValue here, the original which uses rtl::math::approxEqual
91 // is too correct here. Maybe this changes with enhanced precision in aw080
92 // to the better so that this can be reduced to the more precise call again
93 if(basegfx::fTools::equal(fabs(fRotate), F_PI, 0.000000001))
85 // we handle cropping, so when no width or no height, content will be empty,
86 // so only do something when we have a width and a height
87 if(!aObjectScale.equalZero())
94 {
88 {
95 aScale.setX(aScale.getX() * -1.0);
96 aScale.setY(aScale.getY() * -1.0);
97 fRotate = 0.0;
98 }
89 // calculate crop distances in unit coordinates. They are already combined with CropScaleFactor, thus
90 // are relative only to object scale
91 const double fBackScaleX(basegfx::fTools::equalZero(aObjectScale.getX()) ? 1.0 : 1.0 / fabs(aObjectScale.getX()));
92 const double fBackScaleY(basegfx::fTools::equalZero(aObjectScale.getY()) ? 1.0 : 1.0 / fabs(aObjectScale.getY()));
93 const double fLeft(getCropLeft() * fBackScaleX);
94 const double fTop(getCropTop() * fBackScaleY);
95 const double fRight(getCropRight() * fBackScaleX);
96 const double fBottom(getCropBottom() * fBackScaleY);
99
97
100 // create target translate and scale
101 const bool bMirroredX(aScale.getX() < 0.0);
102 const bool bMirroredY(aScale.getY() < 0.0);
103 basegfx::B2DVector aTargetScale(aScale);
104 basegfx::B2DVector aTargetTranslate(aTranslate);
98 // calc new unit range for comparisons; the original range is the unit range
99 const basegfx::B2DRange aUnitRange(0.0, 0.0, 1.0, 1.0);
100 const basegfx::B2DRange aNewRange(
101 -fLeft,
102 -fTop,
103 1.0 + fRight,
104 1.0 + fBottom);
105
105
106 if(bMirroredX)
107 {
108 aTargetTranslate.setX(aTargetTranslate.getX() + getCropRight());
109 aTargetScale.setX(aTargetScale.getX() - getCropLeft() - getCropRight());
110 }
111 else
112 {
113 aTargetTranslate.setX(aTargetTranslate.getX() - getCropLeft());
114 aTargetScale.setX(aTargetScale.getX() + getCropRight() + getCropLeft());
115 }
106 // if we have no overlap the crop has removed everything, so we do only
107 // have to create content if this is not the case
108 if(aNewRange.overlaps(aUnitRange))
109 {
110 // create new transform; first take out old transform to get
111 // to unit coordinates by inverting. Inverting should be flawless
112 // since we already cheched that object size is not zero in X or Y
113 basegfx::B2DHomMatrix aNewTransform(getTransformation());
116
114
117 if(bMirroredY)
118 {
119 aTargetTranslate.setY(aTargetTranslate.getY() + getCropBottom());
120 aTargetScale.setY(aTargetScale.getY() - getCropTop() - getCropBottom());
121 }
122 else
123 {
124 aTargetTranslate.setY(aTargetTranslate.getY() - getCropTop());
125 aTargetScale.setY(aTargetScale.getY() + getCropBottom() + getCropTop());
126 }
115 aNewTransform.invert();
127
116
128 // create ranges to make comparisons
129 const basegfx::B2DRange aCurrent(
130 aTranslate.getX(), aTranslate.getY(),
131 aTranslate.getX() + aScale.getX(), aTranslate.getY() + aScale.getY());
132 const basegfx::B2DRange aCropped(
133 aTargetTranslate.getX(), aTargetTranslate.getY(),
134 aTargetTranslate.getX() + aTargetScale.getX(), aTargetTranslate.getY() + aTargetScale.getY());
117 // apply crop enlargement in unit coordinates
118 aNewTransform = basegfx::tools::createScaleTranslateB2DHomMatrix(
119 aNewRange.getRange(),
120 aNewRange.getMinimum()) * aNewTransform;
135
121
136 if(aCropped.isEmpty())
137 {
138 // nothing to return since cropped content is completely empty
139 }
140 else if(aCurrent.equal(aCropped))
141 {
142 // no crop, just use content
143 xRetval = getChildren();
144 }
145 else
146 {
147 // build new combined content transformation
148 basegfx::B2DHomMatrix aNewObjectTransform(getTransformation());
122 // apply original transformation. Since we have manipulated the crop
123 // in unit coordinates we do not need to care about mirroring or
124 // a corrected point for eventual shear or rotation, this all comes for
125 // free
126 aNewTransform = getTransformation() * aNewTransform;
149
127
150 // remove content transform by inverting
151 aNewObjectTransform.invert();
128 // prepare TransformPrimitive2D with xPrimitive
129 const Primitive2DReference xTransformPrimitive(
130 new TransformPrimitive2D(
131 aNewTransform,
132 getChildren()));
152
133
153 // add target values and original shear/rotate
154 aNewObjectTransform = basegfx::tools::createScaleShearXRotateTranslateB2DHomMatrix(
155 aTargetScale.getX(),
156 aTargetScale.getY(),
157 fShearX,
158 fRotate,
159 aTargetTranslate.getX(),
160 aTargetTranslate.getY())
161 * aNewObjectTransform;
134 if(aUnitRange.isInside(aNewRange))
135 {
136 // the new range is completely inside the old range (unit range),
137 // so no masking is needed
138 xRetval = Primitive2DSequence(&xTransformPrimitive, 1);
139 }
140 else
141 {
142 // mask with original object's bounds
143 basegfx::B2DPolyPolygon aMaskPolyPolygon(basegfx::tools::createUnitPolygon());
144 aMaskPolyPolygon.transform(getTransformation());
162
145
163 // prepare TransformPrimitive2D with xPrimitive
164 const Primitive2DReference xTransformPrimitive(
165 new TransformPrimitive2D(
166 aNewObjectTransform,
167 getChildren()));
146 // create maskPrimitive with aMaskPolyPolygon and aMaskContentVector
147 const Primitive2DReference xMask(
148 new MaskPrimitive2D(
149 aMaskPolyPolygon,
150 Primitive2DSequence(&xTransformPrimitive, 1)));
168
151
169 if(aCurrent.isInside(aCropped))
170 {
171 // crop just shrunk so that its inside content,
172 // no need to use a mask since not really cropped.
173 xRetval = Primitive2DSequence(&xTransformPrimitive, 1);
152 xRetval = Primitive2DSequence(&xMask, 1);
153 }
174 }
154 }
175 else
176 {
177 // mask with original object's bounds
178 basegfx::B2DPolyPolygon aMaskPolyPolygon(basegfx::tools::createUnitPolygon());
179 aMaskPolyPolygon.transform(getTransformation());
180
181 // create maskPrimitive with aMaskPolyPolygon and aMaskContentVector
182 const Primitive2DReference xMask(
183 new MaskPrimitive2D(
184 aMaskPolyPolygon,
185 Primitive2DSequence(&xTransformPrimitive, 1)));
186
187 xRetval = Primitive2DSequence(&xMask, 1);
188 }
189 }
190 }
191
192 return xRetval;
193 }
194
195 // provide unique ID
196 ImplPrimitrive2DIDBlock(CropPrimitive2D, PRIMITIVE2D_ID_CROPPRIMITIVE2D)
197
198 } // end of namespace primitive2d
199} // end of namespace drawinglayer
200
201//////////////////////////////////////////////////////////////////////////////
202// eof
155 }
156 }
157
158 return xRetval;
159 }
160
161 // provide unique ID
162 ImplPrimitrive2DIDBlock(CropPrimitive2D, PRIMITIVE2D_ID_CROPPRIMITIVE2D)
163
164 } // end of namespace primitive2d
165} // end of namespace drawinglayer
166
167//////////////////////////////////////////////////////////////////////////////
168// eof