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/processor3d/cutfindprocessor3d.hxx>
32 #include <drawinglayer/primitive3d/drawinglayer_primitivetypes3d.hxx>
33 #include <drawinglayer/primitive3d/transformprimitive3d.hxx>
34 #include <drawinglayer/primitive3d/hatchtextureprimitive3d.hxx>
35 #include <drawinglayer/primitive3d/polypolygonprimitive3d.hxx>
36 #include <basegfx/polygon/b3dpolygon.hxx>
37 #include <basegfx/polygon/b3dpolygontools.hxx>
38 #include <basegfx/polygon/b3dpolypolygontools.hxx>
39 #include <drawinglayer/primitive3d/hiddengeometryprimitive3d.hxx>
40 
41 //////////////////////////////////////////////////////////////////////////////
42 
43 namespace drawinglayer
44 {
45 	namespace processor3d
46 	{
47         CutFindProcessor::CutFindProcessor(const geometry::ViewInformation3D& rViewInformation,
48             const basegfx::B3DPoint& rFront,
49             const basegfx::B3DPoint& rBack,
50             bool bAnyHit)
51         :   BaseProcessor3D(rViewInformation),
52             maFront(rFront),
53             maBack(rBack),
54             maResult(),
55             maCombinedTransform(),
56             mbAnyHit(bAnyHit),
57 			mbUseInvisiblePrimitiveContent(true)
58         {
59         }
60 
61         void CutFindProcessor::processBasePrimitive3D(const primitive3d::BasePrimitive3D& rCandidate)
62         {
63 			if(getAnyHit() && maResult.size())
64 			{
65 				// stop processing as soon as a hit was recognized
66 				return;
67 			}
68 
69             // it is a BasePrimitive3D implementation, use getPrimitive3DID() call for switch
70 			switch(rCandidate.getPrimitive3DID())
71 			{
72 				case PRIMITIVE3D_ID_TRANSFORMPRIMITIVE3D :
73 				{
74 					// transform group.
75 					const primitive3d::TransformPrimitive3D& rPrimitive = static_cast< const primitive3d::TransformPrimitive3D& >(rCandidate);
76 
77 					// remember old and transform front, back to object coordinates
78 					const basegfx::B3DPoint aLastFront(maFront);
79 					const basegfx::B3DPoint aLastBack(maBack);
80 					basegfx::B3DHomMatrix aInverseTrans(rPrimitive.getTransformation());
81 					aInverseTrans.invert();
82 					maFront *= aInverseTrans;
83 					maBack *= aInverseTrans;
84 
85 					// remember current and create new transformation; add new object transform from right side
86 					const geometry::ViewInformation3D aLastViewInformation3D(getViewInformation3D());
87 					const geometry::ViewInformation3D aNewViewInformation3D(
88 						aLastViewInformation3D.getObjectTransformation() * rPrimitive.getTransformation(),
89 						aLastViewInformation3D.getOrientation(),
90 						aLastViewInformation3D.getProjection(),
91 						aLastViewInformation3D.getDeviceToView(),
92 						aLastViewInformation3D.getViewTime(),
93 						aLastViewInformation3D.getExtendedInformationSequence());
94 					updateViewInformation(aNewViewInformation3D);
95 
96                     // #i102956# remember needed back-transform for found cuts (combine from right side)
97                     const basegfx::B3DHomMatrix aLastCombinedTransform(maCombinedTransform);
98                     maCombinedTransform = maCombinedTransform * rPrimitive.getTransformation();
99 
100 					// let break down
101 					process(rPrimitive.getChildren());
102 
103 					// restore transformations and front, back
104                     maCombinedTransform = aLastCombinedTransform;
105 					updateViewInformation(aLastViewInformation3D);
106 					maFront = aLastFront;
107 					maBack = aLastBack;
108 					break;
109 				}
110 				case PRIMITIVE3D_ID_POLYGONHAIRLINEPRIMITIVE3D :
111 				{
112 					// PolygonHairlinePrimitive3D, not used for hit test with planes, ignore. This
113 					// means that also thick line expansion will not be hit-tested as
114 					// PolyPolygonMaterialPrimitive3D
115                     break;
116 				}
117 				case PRIMITIVE3D_ID_HATCHTEXTUREPRIMITIVE3D :
118 				{
119 					// #i97321#
120 					// For HatchTexturePrimitive3D, do not use the decomposition since it will produce
121 					// clipped hatch lines in 3D. It can be used when the hatch also has a filling, but for
122 					// simplicity, just use the children which are the PolyPolygonMaterialPrimitive3D
123 					// which define the hatched areas anyways; for HitTest this is more than adequate
124 					const primitive3d::HatchTexturePrimitive3D& rPrimitive = static_cast< const primitive3d::HatchTexturePrimitive3D& >(rCandidate);
125 					process(rPrimitive.getChildren());
126 					break;
127 				}
128 				case PRIMITIVE3D_ID_HIDDENGEOMETRYPRIMITIVE3D :
129 				{
130 					// HiddenGeometryPrimitive3D; the default decomposition would return an empty seqence,
131 					// so force this primitive to process it's children directly if the switch is set
132 					// (which is the default). Else, ignore invisible content
133 				    const primitive3d::HiddenGeometryPrimitive3D& rHiddenGeometry(static_cast< const primitive3d::HiddenGeometryPrimitive3D& >(rCandidate));
134        			    const primitive3d::Primitive3DSequence& rChildren = rHiddenGeometry.getChildren();
135 
136                     if(rChildren.hasElements())
137                     {
138                         if(getUseInvisiblePrimitiveContent())
139 					    {
140                             process(rChildren);
141 					    }
142                     }
143 
144                     break;
145 				}
146                 case PRIMITIVE3D_ID_UNIFIEDTRANSPARENCETEXTUREPRIMITIVE3D :
147                 {
148 					const primitive3d::UnifiedTransparenceTexturePrimitive3D& rPrimitive = static_cast< const primitive3d::UnifiedTransparenceTexturePrimitive3D& >(rCandidate);
149        			    const primitive3d::Primitive3DSequence rChildren = rPrimitive.getChildren();
150 
151                     if(rChildren.getLength())
152                     {
153     			        if(1.0 <= rPrimitive.getTransparence())
154                         {
155                             // not visible, but use for HitTest
156 					        if(getUseInvisiblePrimitiveContent())
157 					        {
158            						process(rChildren);
159                             }
160                         }
161                         else if(rPrimitive.getTransparence() >= 0.0 && rPrimitive.getTransparence() < 1.0)
162 			            {
163                             // visible; use content
164     						process(rChildren);
165                         }
166                     }
167 
168                     break;
169                 }
170 				case PRIMITIVE3D_ID_POLYPOLYGONMATERIALPRIMITIVE3D :
171 				{
172 					// PolyPolygonMaterialPrimitive3D
173 					const primitive3d::PolyPolygonMaterialPrimitive3D& rPrimitive = static_cast< const primitive3d::PolyPolygonMaterialPrimitive3D& >(rCandidate);
174 
175                     if(!maFront.equal(maBack))
176                     {
177            			    const basegfx::B3DPolyPolygon& rPolyPolygon = rPrimitive.getB3DPolyPolygon();
178                         const sal_uInt32 nPolyCount(rPolyPolygon.count());
179 
180                         if(nPolyCount)
181                         {
182            			        const basegfx::B3DPolygon aPolygon(rPolyPolygon.getB3DPolygon(0));
183                             const sal_uInt32 nPointCount(aPolygon.count());
184 
185                             if(nPointCount > 2)
186                             {
187                                 const basegfx::B3DVector aPlaneNormal(aPolygon.getNormal());
188 
189                                 if(!aPlaneNormal.equalZero())
190                                 {
191                                     const basegfx::B3DPoint aPointOnPlane(aPolygon.getB3DPoint(0));
192                                     double fCut(0.0);
193 
194                                     if(basegfx::tools::getCutBetweenLineAndPlane(aPlaneNormal, aPointOnPlane, maFront, maBack, fCut))
195                                     {
196                                         const basegfx::B3DPoint aCutPoint(basegfx::interpolate(maFront, maBack, fCut));
197 
198                                         if(basegfx::tools::isInside(rPolyPolygon, aCutPoint, false))
199                                         {
200                                             // #i102956# add result. Do not forget to do this in the coordinate
201                                             // system the processor get started with, so use the collected
202                                             // combined transformation from processed TransformPrimitive3D's
203                                             maResult.push_back(maCombinedTransform * aCutPoint);
204                                         }
205                                     }
206                                 }
207                             }
208                         }
209                     }
210 
211                     break;
212 				}
213 				default :
214 				{
215 					// process recursively
216 					process(rCandidate.get3DDecomposition(getViewInformation3D()));
217 					break;
218 				}
219             }
220         }
221 	} // end of namespace processor3d
222 } // end of namespace drawinglayer
223 
224 //////////////////////////////////////////////////////////////////////////////
225 // eof
226