xref: /AOO41X/main/drawinglayer/source/primitive2d/cropprimitive2d.cxx (revision ddde725d65c83fe3ba1186d46f6e3e08f12ba47e)
1*ddde725dSArmin Le Grand /**************************************************************
2*ddde725dSArmin Le Grand  *
3*ddde725dSArmin Le Grand  * Licensed to the Apache Software Foundation (ASF) under one
4*ddde725dSArmin Le Grand  * or more contributor license agreements.  See the NOTICE file
5*ddde725dSArmin Le Grand  * distributed with this work for additional information
6*ddde725dSArmin Le Grand  * regarding copyright ownership.  The ASF licenses this file
7*ddde725dSArmin Le Grand  * to you under the Apache License, Version 2.0 (the
8*ddde725dSArmin Le Grand  * "License"); you may not use this file except in compliance
9*ddde725dSArmin Le Grand  * with the License.  You may obtain a copy of the License at
10*ddde725dSArmin Le Grand  *
11*ddde725dSArmin Le Grand  *   http://www.apache.org/licenses/LICENSE-2.0
12*ddde725dSArmin Le Grand  *
13*ddde725dSArmin Le Grand  * Unless required by applicable law or agreed to in writing,
14*ddde725dSArmin Le Grand  * software distributed under the License is distributed on an
15*ddde725dSArmin Le Grand  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*ddde725dSArmin Le Grand  * KIND, either express or implied.  See the License for the
17*ddde725dSArmin Le Grand  * specific language governing permissions and limitations
18*ddde725dSArmin Le Grand  * under the License.
19*ddde725dSArmin Le Grand  *
20*ddde725dSArmin Le Grand  *************************************************************/
21*ddde725dSArmin Le Grand 
22*ddde725dSArmin Le Grand // MARKER(update_precomp.py): autogen include statement, do not remove
23*ddde725dSArmin Le Grand #include "precompiled_drawinglayer.hxx"
24*ddde725dSArmin Le Grand 
25*ddde725dSArmin Le Grand #include <drawinglayer/primitive2d/cropprimitive2d.hxx>
26*ddde725dSArmin Le Grand #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
27*ddde725dSArmin Le Grand #include <basegfx/matrix/b2dhommatrix.hxx>
28*ddde725dSArmin Le Grand #include <basegfx/matrix/b2dhommatrixtools.hxx>
29*ddde725dSArmin Le Grand #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
30*ddde725dSArmin Le Grand #include <basegfx/polygon/b2dpolygon.hxx>
31*ddde725dSArmin Le Grand #include <basegfx/polygon/b2dpolygontools.hxx>
32*ddde725dSArmin Le Grand #include <drawinglayer/primitive2d/maskprimitive2d.hxx>
33*ddde725dSArmin Le Grand 
34*ddde725dSArmin Le Grand //////////////////////////////////////////////////////////////////////////////
35*ddde725dSArmin Le Grand 
36*ddde725dSArmin Le Grand using namespace com::sun::star;
37*ddde725dSArmin Le Grand 
38*ddde725dSArmin Le Grand //////////////////////////////////////////////////////////////////////////////
39*ddde725dSArmin Le Grand 
40*ddde725dSArmin Le Grand namespace drawinglayer
41*ddde725dSArmin Le Grand {
42*ddde725dSArmin Le Grand     namespace primitive2d
43*ddde725dSArmin Le Grand     {
44*ddde725dSArmin Le Grand         CropPrimitive2D::CropPrimitive2D(
45*ddde725dSArmin Le Grand             const Primitive2DSequence& rChildren,
46*ddde725dSArmin Le Grand             const basegfx::B2DHomMatrix& rTransformation,
47*ddde725dSArmin Le Grand             double fCropLeft,
48*ddde725dSArmin Le Grand             double fCropTop,
49*ddde725dSArmin Le Grand             double fCropRight,
50*ddde725dSArmin Le Grand             double fCropBottom)
51*ddde725dSArmin Le Grand         :   GroupPrimitive2D(rChildren),
52*ddde725dSArmin Le Grand             maTransformation(rTransformation),
53*ddde725dSArmin Le Grand             mfCropLeft(fCropLeft),
54*ddde725dSArmin Le Grand             mfCropTop(fCropTop),
55*ddde725dSArmin Le Grand             mfCropRight(fCropRight),
56*ddde725dSArmin Le Grand             mfCropBottom(fCropBottom)
57*ddde725dSArmin Le Grand         {
58*ddde725dSArmin Le Grand         }
59*ddde725dSArmin Le Grand 
60*ddde725dSArmin Le Grand         bool CropPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
61*ddde725dSArmin Le Grand         {
62*ddde725dSArmin Le Grand             if(GroupPrimitive2D::operator==(rPrimitive))
63*ddde725dSArmin Le Grand             {
64*ddde725dSArmin Le Grand                 const CropPrimitive2D& rCompare = static_cast< const CropPrimitive2D& >(rPrimitive);
65*ddde725dSArmin Le Grand 
66*ddde725dSArmin Le Grand                 return (getTransformation() == rCompare.getTransformation()
67*ddde725dSArmin Le Grand                     && getCropLeft() == rCompare.getCropLeft()
68*ddde725dSArmin Le Grand                     && getCropTop() == rCompare.getCropTop()
69*ddde725dSArmin Le Grand                     && getCropRight() == rCompare.getCropRight()
70*ddde725dSArmin Le Grand                     && getCropBottom() == rCompare.getCropBottom());
71*ddde725dSArmin Le Grand             }
72*ddde725dSArmin Le Grand 
73*ddde725dSArmin Le Grand             return false;
74*ddde725dSArmin Le Grand         }
75*ddde725dSArmin Le Grand 
76*ddde725dSArmin Le Grand         Primitive2DSequence CropPrimitive2D::get2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
77*ddde725dSArmin Le Grand         {
78*ddde725dSArmin Le Grand             Primitive2DSequence xRetval;
79*ddde725dSArmin Le Grand 
80*ddde725dSArmin Le Grand             if(getChildren().hasElements())
81*ddde725dSArmin Le Grand             {
82*ddde725dSArmin Le Grand                 // decompose to have current translate and scale
83*ddde725dSArmin Le Grand                 basegfx::B2DVector aScale, aTranslate;
84*ddde725dSArmin Le Grand                 double fRotate, fShearX;
85*ddde725dSArmin Le Grand 
86*ddde725dSArmin Le Grand                 getTransformation().decompose(aScale, aTranslate, fRotate, fShearX);
87*ddde725dSArmin Le Grand 
88*ddde725dSArmin Le Grand                 // detect 180 degree rotation, this is the same as mirrored in X and Y,
89*ddde725dSArmin Le Grand                 // thus change to mirroring. Prefer mirroring here. Use the equal call
90*ddde725dSArmin Le Grand                 // with getSmallValue here, the original which uses rtl::math::approxEqual
91*ddde725dSArmin Le Grand                 // is too correct here. Maybe this changes with enhanced precision in aw080
92*ddde725dSArmin Le Grand                 // to the better so that this can be reduced to the more precise call again
93*ddde725dSArmin Le Grand                 if(basegfx::fTools::equal(fRotate, F_PI, 0.000000001))
94*ddde725dSArmin Le Grand                 {
95*ddde725dSArmin Le Grand                     aScale.setX(aScale.getX() * -1.0);
96*ddde725dSArmin Le Grand                     aScale.setY(aScale.getY() * -1.0);
97*ddde725dSArmin Le Grand                     fRotate = 0.0;
98*ddde725dSArmin Le Grand                 }
99*ddde725dSArmin Le Grand 
100*ddde725dSArmin Le Grand                 // create target translate and scale
101*ddde725dSArmin Le Grand                 const bool bMirroredX(aScale.getX() < 0.0);
102*ddde725dSArmin Le Grand                 const bool bMirroredY(aScale.getY() < 0.0);
103*ddde725dSArmin Le Grand                 basegfx::B2DVector aTargetScale(aScale);
104*ddde725dSArmin Le Grand                 basegfx::B2DVector aTargetTranslate(aTranslate);
105*ddde725dSArmin Le Grand 
106*ddde725dSArmin Le Grand                 if(bMirroredX)
107*ddde725dSArmin Le Grand                 {
108*ddde725dSArmin Le Grand                     aTargetTranslate.setX(aTargetTranslate.getX() + getCropRight());
109*ddde725dSArmin Le Grand                     aTargetScale.setX(aTargetScale.getX() - getCropLeft() - getCropRight());
110*ddde725dSArmin Le Grand                 }
111*ddde725dSArmin Le Grand                 else
112*ddde725dSArmin Le Grand                 {
113*ddde725dSArmin Le Grand                     aTargetTranslate.setX(aTargetTranslate.getX() - getCropLeft());
114*ddde725dSArmin Le Grand                     aTargetScale.setX(aTargetScale.getX() + getCropRight() + getCropLeft());
115*ddde725dSArmin Le Grand                 }
116*ddde725dSArmin Le Grand 
117*ddde725dSArmin Le Grand                 if(bMirroredY)
118*ddde725dSArmin Le Grand                 {
119*ddde725dSArmin Le Grand                     aTargetTranslate.setY(aTargetTranslate.getY() + getCropBottom());
120*ddde725dSArmin Le Grand                     aTargetScale.setY(aTargetScale.getY() - getCropTop() - getCropBottom());
121*ddde725dSArmin Le Grand                 }
122*ddde725dSArmin Le Grand                 else
123*ddde725dSArmin Le Grand                 {
124*ddde725dSArmin Le Grand                     aTargetTranslate.setY(aTargetTranslate.getY() - getCropTop());
125*ddde725dSArmin Le Grand                     aTargetScale.setY(aTargetScale.getY() + getCropBottom() + getCropTop());
126*ddde725dSArmin Le Grand                 }
127*ddde725dSArmin Le Grand 
128*ddde725dSArmin Le Grand                 // create ranges to make comparisons
129*ddde725dSArmin Le Grand                 const basegfx::B2DRange aCurrent(
130*ddde725dSArmin Le Grand                     aTranslate.getX(), aTranslate.getY(),
131*ddde725dSArmin Le Grand                     aTranslate.getX() + aScale.getX(), aTranslate.getY() + aScale.getY());
132*ddde725dSArmin Le Grand                 const basegfx::B2DRange aCropped(
133*ddde725dSArmin Le Grand                     aTargetTranslate.getX(), aTargetTranslate.getY(),
134*ddde725dSArmin Le Grand                     aTargetTranslate.getX() + aTargetScale.getX(), aTargetTranslate.getY() + aTargetScale.getY());
135*ddde725dSArmin Le Grand 
136*ddde725dSArmin Le Grand                 if(aCropped.isEmpty())
137*ddde725dSArmin Le Grand                 {
138*ddde725dSArmin Le Grand                     // nothing to return since cropped content is completely empty
139*ddde725dSArmin Le Grand                 }
140*ddde725dSArmin Le Grand                 else if(aCurrent.equal(aCropped))
141*ddde725dSArmin Le Grand                 {
142*ddde725dSArmin Le Grand                     // no crop, just use content
143*ddde725dSArmin Le Grand                     xRetval = getChildren();
144*ddde725dSArmin Le Grand                 }
145*ddde725dSArmin Le Grand                 else
146*ddde725dSArmin Le Grand                 {
147*ddde725dSArmin Le Grand                     // build new combined content transformation
148*ddde725dSArmin Le Grand                     basegfx::B2DHomMatrix aNewObjectTransform(getTransformation());
149*ddde725dSArmin Le Grand 
150*ddde725dSArmin Le Grand                     // remove content transform by inverting
151*ddde725dSArmin Le Grand                     aNewObjectTransform.invert();
152*ddde725dSArmin Le Grand 
153*ddde725dSArmin Le Grand                     // add target values and original shear/rotate
154*ddde725dSArmin Le Grand                     aNewObjectTransform = basegfx::tools::createScaleShearXRotateTranslateB2DHomMatrix(
155*ddde725dSArmin Le Grand                         aTargetScale.getX(),
156*ddde725dSArmin Le Grand                         aTargetScale.getY(),
157*ddde725dSArmin Le Grand                         fShearX,
158*ddde725dSArmin Le Grand                         fRotate,
159*ddde725dSArmin Le Grand                         aTargetTranslate.getX(),
160*ddde725dSArmin Le Grand                         aTargetTranslate.getY())
161*ddde725dSArmin Le Grand                             * aNewObjectTransform;
162*ddde725dSArmin Le Grand 
163*ddde725dSArmin Le Grand                     // prepare TransformPrimitive2D with xPrimitive
164*ddde725dSArmin Le Grand                     const Primitive2DReference xTransformPrimitive(
165*ddde725dSArmin Le Grand                         new TransformPrimitive2D(
166*ddde725dSArmin Le Grand                             aNewObjectTransform,
167*ddde725dSArmin Le Grand                             getChildren()));
168*ddde725dSArmin Le Grand 
169*ddde725dSArmin Le Grand                     if(aCurrent.isInside(aCropped))
170*ddde725dSArmin Le Grand                     {
171*ddde725dSArmin Le Grand                         // crop just shrunk so that its inside content,
172*ddde725dSArmin Le Grand                         // no need to use a mask since not really cropped.
173*ddde725dSArmin Le Grand                         xRetval = Primitive2DSequence(&xTransformPrimitive, 1);
174*ddde725dSArmin Le Grand                     }
175*ddde725dSArmin Le Grand                     else
176*ddde725dSArmin Le Grand                     {
177*ddde725dSArmin Le Grand                         // mask with original object's bounds
178*ddde725dSArmin Le Grand                         basegfx::B2DPolyPolygon aMaskPolyPolygon(basegfx::tools::createUnitPolygon());
179*ddde725dSArmin Le Grand                         aMaskPolyPolygon.transform(getTransformation());
180*ddde725dSArmin Le Grand 
181*ddde725dSArmin Le Grand                         // create maskPrimitive with aMaskPolyPolygon and aMaskContentVector
182*ddde725dSArmin Le Grand                         const Primitive2DReference xMask(
183*ddde725dSArmin Le Grand                             new MaskPrimitive2D(
184*ddde725dSArmin Le Grand                                 aMaskPolyPolygon,
185*ddde725dSArmin Le Grand                                 Primitive2DSequence(&xTransformPrimitive, 1)));
186*ddde725dSArmin Le Grand 
187*ddde725dSArmin Le Grand                         xRetval = Primitive2DSequence(&xMask, 1);
188*ddde725dSArmin Le Grand                     }
189*ddde725dSArmin Le Grand                 }
190*ddde725dSArmin Le Grand             }
191*ddde725dSArmin Le Grand 
192*ddde725dSArmin Le Grand             return xRetval;
193*ddde725dSArmin Le Grand         }
194*ddde725dSArmin Le Grand 
195*ddde725dSArmin Le Grand         // provide unique ID
196*ddde725dSArmin Le Grand         ImplPrimitrive2DIDBlock(CropPrimitive2D, PRIMITIVE2D_ID_CROPPRIMITIVE2D)
197*ddde725dSArmin Le Grand 
198*ddde725dSArmin Le Grand     } // end of namespace primitive2d
199*ddde725dSArmin Le Grand } // end of namespace drawinglayer
200*ddde725dSArmin Le Grand 
201*ddde725dSArmin Le Grand //////////////////////////////////////////////////////////////////////////////
202*ddde725dSArmin Le Grand // eof
203