| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_svx.hxx" |
| #include <svx/sdr/contact/viewcontactofe3dscene.hxx> |
| #include <svx/polysc3d.hxx> |
| #include <svx/sdr/contact/displayinfo.hxx> |
| #include <svx/sdr/contact/viewobjectcontact.hxx> |
| #include <basegfx/polygon/b2dpolygontools.hxx> |
| #include <basegfx/color/bcolor.hxx> |
| #include <drawinglayer/primitive2d/polygonprimitive2d.hxx> |
| #include <svx/sdr/primitive2d/sdrattributecreator.hxx> |
| #include <svx/sdr/contact/viewobjectcontactofe3dscene.hxx> |
| #include <basegfx/matrix/b2dhommatrix.hxx> |
| #include <basegfx/range/b3drange.hxx> |
| #include <drawinglayer/primitive3d/baseprimitive3d.hxx> |
| #include <svx/sdr/contact/viewcontactofe3d.hxx> |
| #include <drawinglayer/primitive2d/sceneprimitive2d.hxx> |
| #include <drawinglayer/primitive3d/transformprimitive3d.hxx> |
| #include <drawinglayer/primitive2d/sdrdecompositiontools2d.hxx> |
| |
| ////////////////////////////////////////////////////////////////////////////// |
| |
| using namespace com::sun::star; |
| |
| ////////////////////////////////////////////////////////////////////////////// |
| |
| namespace |
| { |
| // pActiveVC is only true if ghosted is still activated and maybe needs to be switched off in this path |
| void createSubPrimitive3DVector( |
| const sdr::contact::ViewContact& rCandidate, |
| drawinglayer::primitive3d::Primitive3DSequence& o_rAllTarget, |
| drawinglayer::primitive3d::Primitive3DSequence* o_pVisibleTarget, |
| const SetOfByte* pVisibleLayerSet, |
| const bool bTestSelectedVisibility) |
| { |
| const sdr::contact::ViewContactOfE3dScene* pViewContactOfE3dScene = dynamic_cast< const sdr::contact::ViewContactOfE3dScene* >(&rCandidate); |
| |
| if(pViewContactOfE3dScene) |
| { |
| const sal_uInt32 nChildrenCount(rCandidate.GetObjectCount()); |
| |
| if(nChildrenCount) |
| { |
| // provide new collection sequences |
| drawinglayer::primitive3d::Primitive3DSequence aNewAllTarget; |
| drawinglayer::primitive3d::Primitive3DSequence aNewVisibleTarget; |
| |
| // add children recursively |
| for(sal_uInt32 a(0L); a < nChildrenCount; a++) |
| { |
| createSubPrimitive3DVector( |
| rCandidate.GetViewContact(a), |
| aNewAllTarget, |
| o_pVisibleTarget ? &aNewVisibleTarget : 0, |
| pVisibleLayerSet, |
| bTestSelectedVisibility); |
| } |
| |
| // create transform primitive for the created content combining content and transformtion |
| const drawinglayer::primitive3d::Primitive3DReference xReference(new drawinglayer::primitive3d::TransformPrimitive3D( |
| pViewContactOfE3dScene->GetE3dScene().GetTransform(), |
| aNewAllTarget)); |
| |
| // add created content to all target |
| drawinglayer::primitive3d::appendPrimitive3DReferenceToPrimitive3DSequence(o_rAllTarget, xReference); |
| |
| // add created content to visibiel target if exists |
| if(o_pVisibleTarget) |
| { |
| drawinglayer::primitive3d::appendPrimitive3DReferenceToPrimitive3DSequence(*o_pVisibleTarget, xReference); |
| } |
| } |
| } |
| else |
| { |
| // access view independent representation of rCandidate |
| const sdr::contact::ViewContactOfE3d* pViewContactOfE3d = dynamic_cast< const sdr::contact::ViewContactOfE3d* >(&rCandidate); |
| |
| if(pViewContactOfE3d) |
| { |
| drawinglayer::primitive3d::Primitive3DSequence xPrimitive3DSeq(pViewContactOfE3d->getViewIndependentPrimitive3DSequence()); |
| |
| if(xPrimitive3DSeq.hasElements()) |
| { |
| // add to all target vector |
| drawinglayer::primitive3d::appendPrimitive3DSequenceToPrimitive3DSequence(o_rAllTarget, xPrimitive3DSeq); |
| |
| if(o_pVisibleTarget) |
| { |
| // test visibility. Primitive is visible when both tests are true (AND) |
| bool bVisible(true); |
| |
| if(pVisibleLayerSet) |
| { |
| // test layer visibility |
| const E3dObject& rE3dObject = pViewContactOfE3d->GetE3dObject(); |
| const SdrLayerID aLayerID(rE3dObject.GetLayer()); |
| |
| bVisible = pVisibleLayerSet->IsSet(aLayerID); |
| } |
| |
| if(bVisible && bTestSelectedVisibility) |
| { |
| // test selected visibility (see 3D View's DrawMarkedObj implementation) |
| const E3dObject& rE3dObject = pViewContactOfE3d->GetE3dObject(); |
| |
| bVisible = rE3dObject.GetSelected(); |
| } |
| |
| if(bVisible && o_pVisibleTarget) |
| { |
| // add to visible target vector |
| drawinglayer::primitive3d::appendPrimitive3DSequenceToPrimitive3DSequence(*o_pVisibleTarget, xPrimitive3DSeq); |
| } |
| } |
| } |
| } |
| } |
| } |
| } // end of anonymous namespace |
| |
| ////////////////////////////////////////////////////////////////////////////// |
| |
| namespace sdr |
| { |
| namespace contact |
| { |
| // Create a Object-Specific ViewObjectContact, set ViewContact and |
| // ObjectContact. Always needs to return something. |
| ViewObjectContact& ViewContactOfE3dScene::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact) |
| { |
| ViewObjectContact* pRetval = new ViewObjectContactOfE3dScene(rObjectContact, *this); |
| DBG_ASSERT(pRetval, "ViewContactOfE3dScene::CreateObjectSpecificViewObjectContact() failed (!)"); |
| |
| return *pRetval; |
| } |
| |
| ViewContactOfE3dScene::ViewContactOfE3dScene(E3dScene& rScene) |
| : ViewContactOfSdrObj(rScene), |
| maViewInformation3D(), |
| maObjectTransformation(), |
| maSdrSceneAttribute(), |
| maSdrLightingAttribute() |
| { |
| } |
| |
| void ViewContactOfE3dScene::createViewInformation3D(const basegfx::B3DRange& rContentRange) |
| { |
| basegfx::B3DHomMatrix aTransformation; |
| basegfx::B3DHomMatrix aOrientation; |
| basegfx::B3DHomMatrix aProjection; |
| basegfx::B3DHomMatrix aDeviceToView; |
| |
| // create transformation (scene as group's transformation) |
| // For historical reasons, the outmost scene's transformation is handles as part of the |
| // view transformation. This means that the BoundRect of the contained 3D Objects is |
| // without that transformation and makes it necessary to NOT add the first scene to the |
| // Primitive3DSequence of contained objects. |
| { |
| aTransformation = GetE3dScene().GetTransform(); |
| } |
| |
| // create orientation (world to camera coordinate system) |
| { |
| // calculate orientation from VRP, VPN and VUV |
| const B3dCamera& rSceneCamera = GetE3dScene().GetCameraSet(); |
| const basegfx::B3DPoint aVRP(rSceneCamera.GetVRP()); |
| const basegfx::B3DVector aVPN(rSceneCamera.GetVRP()); |
| const basegfx::B3DVector aVUV(rSceneCamera.GetVUV()); |
| |
| aOrientation.orientation(aVRP, aVPN, aVUV); |
| } |
| |
| // create projection (camera coordinate system to relative 2d where X,Y and Z are [0.0 .. 1.0]) |
| { |
| const basegfx::B3DHomMatrix aWorldToCamera(aOrientation * aTransformation); |
| basegfx::B3DRange aCameraRange(rContentRange); |
| aCameraRange.transform(aWorldToCamera); |
| |
| // remember Z-Values, but change orientation |
| const double fMinZ(-aCameraRange.getMaxZ()); |
| const double fMaxZ(-aCameraRange.getMinZ()); |
| |
| // construct temorary matrix from world to device. Use unit values here to measure expansion |
| basegfx::B3DHomMatrix aWorldToDevice(aWorldToCamera); |
| const drawinglayer::attribute::SdrSceneAttribute& rSdrSceneAttribute = getSdrSceneAttribute(); |
| |
| if(::com::sun::star::drawing::ProjectionMode_PERSPECTIVE == rSdrSceneAttribute.getProjectionMode()) |
| { |
| aWorldToDevice.frustum(-1.0, 1.0, -1.0, 1.0, fMinZ, fMaxZ); |
| } |
| else |
| { |
| aWorldToDevice.ortho(-1.0, 1.0, -1.0, 1.0, fMinZ, fMaxZ); |
| } |
| |
| // create B3DRange in device. This will create the real used ranges |
| // in camera space. Do not use the Z-Values, though. |
| basegfx::B3DRange aDeviceRange(rContentRange); |
| aDeviceRange.transform(aWorldToDevice); |
| |
| // set projection |
| if(::com::sun::star::drawing::ProjectionMode_PERSPECTIVE == rSdrSceneAttribute.getProjectionMode()) |
| { |
| aProjection.frustum( |
| aDeviceRange.getMinX(), aDeviceRange.getMaxX(), |
| aDeviceRange.getMinY(), aDeviceRange.getMaxY(), |
| fMinZ, fMaxZ); |
| } |
| else |
| { |
| aProjection.ortho( |
| aDeviceRange.getMinX(), aDeviceRange.getMaxX(), |
| aDeviceRange.getMinY(), aDeviceRange.getMaxY(), |
| fMinZ, fMaxZ); |
| } |
| } |
| |
| // create device to view transform |
| { |
| // create standard deviceToView projection for geometry |
| // input is [-1.0 .. 1.0] in X,Y and Z. bring to [0.0 .. 1.0]. Also |
| // necessary to flip Y due to screen orientation |
| // Z is not needed, but will also be brought to [0.0 .. 1.0] |
| aDeviceToView.scale(0.5, -0.5, 0.5); |
| aDeviceToView.translate(0.5, 0.5, 0.5); |
| } |
| |
| const uno::Sequence< beans::PropertyValue > aEmptyProperties; |
| maViewInformation3D = drawinglayer::geometry::ViewInformation3D( |
| aTransformation, aOrientation, aProjection, |
| aDeviceToView, 0.0, aEmptyProperties); |
| } |
| |
| void ViewContactOfE3dScene::createObjectTransformation() |
| { |
| // create 2d Object Transformation from relative point in 2d scene to world |
| const Rectangle& rRectangle = GetE3dScene().GetSnapRect(); |
| |
| maObjectTransformation.set(0, 0, rRectangle.getWidth()); |
| maObjectTransformation.set(1, 1, rRectangle.getHeight()); |
| maObjectTransformation.set(0, 2, rRectangle.Left()); |
| maObjectTransformation.set(1, 2, rRectangle.Top()); |
| } |
| |
| void ViewContactOfE3dScene::createSdrSceneAttribute() |
| { |
| const SfxItemSet& rItemSet = GetE3dScene().GetMergedItemSet(); |
| maSdrSceneAttribute = drawinglayer::primitive2d::createNewSdrSceneAttribute(rItemSet); |
| } |
| |
| void ViewContactOfE3dScene::createSdrLightingAttribute() |
| { |
| const SfxItemSet& rItemSet = GetE3dScene().GetMergedItemSet(); |
| maSdrLightingAttribute = drawinglayer::primitive2d::createNewSdrLightingAttribute(rItemSet); |
| } |
| |
| drawinglayer::primitive2d::Primitive2DSequence ViewContactOfE3dScene::createScenePrimitive2DSequence( |
| const SetOfByte* pLayerVisibility) const |
| { |
| drawinglayer::primitive2d::Primitive2DSequence xRetval; |
| const sal_uInt32 nChildrenCount(GetObjectCount()); |
| |
| if(nChildrenCount) |
| { |
| // create 3d scene primitive with visible content tested against rLayerVisibility |
| drawinglayer::primitive3d::Primitive3DSequence aAllSequence; |
| drawinglayer::primitive3d::Primitive3DSequence aVisibleSequence; |
| const bool bTestLayerVisibility(0 != pLayerVisibility); |
| const bool bTestSelectedVisibility(GetE3dScene().GetDrawOnlySelected()); |
| const bool bTestVisibility(bTestLayerVisibility || bTestSelectedVisibility); |
| |
| // add children recursively. Do NOT start with (*this), this would create |
| // a 3D transformPrimitive for the start scene. While this is theoretically not |
| // a bad thing, for historical reasons the transformation of the outmost scene |
| // is seen as part of the ViewTransformation (see text in createViewInformation3D) |
| for(sal_uInt32 a(0L); a < nChildrenCount; a++) |
| { |
| createSubPrimitive3DVector( |
| GetViewContact(a), |
| aAllSequence, |
| bTestLayerVisibility ? &aVisibleSequence : 0, |
| bTestLayerVisibility ? pLayerVisibility : 0, |
| bTestSelectedVisibility); |
| } |
| |
| const sal_uInt32 nAllSize(aAllSequence.hasElements() ? aAllSequence.getLength() : 0); |
| const sal_uInt32 nVisibleSize(aVisibleSequence.hasElements() ? aVisibleSequence.getLength() : 0); |
| |
| if((bTestVisibility && nVisibleSize) || nAllSize) |
| { |
| // for getting the 3D range using getB3DRangeFromPrimitive3DSequence a ViewInformation3D |
| // needs to be given for evtl. decompositions. At the same time createViewInformation3D |
| // currently is based on creating the target-ViewInformation3D using a given range. To |
| // get the true range, use a neutral ViewInformation3D here. This leaves all matrices |
| // on identity and the time on 0.0. |
| const uno::Sequence< beans::PropertyValue > aEmptyProperties; |
| const drawinglayer::geometry::ViewInformation3D aNeutralViewInformation3D(aEmptyProperties); |
| const basegfx::B3DRange aContentRange( |
| drawinglayer::primitive3d::getB3DRangeFromPrimitive3DSequence(aAllSequence, aNeutralViewInformation3D)); |
| |
| // create 2d primitive 3dscene with generated sub-list from collector |
| const drawinglayer::primitive2d::Primitive2DReference xReference( |
| new drawinglayer::primitive2d::ScenePrimitive2D( |
| bTestVisibility ? aVisibleSequence : aAllSequence, |
| getSdrSceneAttribute(), |
| getSdrLightingAttribute(), |
| getObjectTransformation(), |
| getViewInformation3D(aContentRange))); |
| |
| xRetval = drawinglayer::primitive2d::Primitive2DSequence(&xReference, 1); |
| } |
| } |
| |
| // always append an invisible outline for the cases where no visible content exists |
| drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(xRetval, |
| drawinglayer::primitive2d::createHiddenGeometryPrimitives2D( |
| false, getObjectTransformation())); |
| |
| return xRetval; |
| } |
| |
| drawinglayer::primitive2d::Primitive2DSequence ViewContactOfE3dScene::createViewIndependentPrimitive2DSequence() const |
| { |
| drawinglayer::primitive2d::Primitive2DSequence xRetval; |
| |
| if(GetObjectCount()) |
| { |
| // create a default ScenePrimitive2D (without visibility test of members) |
| xRetval = createScenePrimitive2DSequence(0); |
| } |
| |
| return xRetval; |
| } |
| |
| void ViewContactOfE3dScene::ActionChanged() |
| { |
| // call parent |
| ViewContactOfSdrObj::ActionChanged(); |
| |
| // mark locally cached values as invalid |
| maViewInformation3D = drawinglayer::geometry::ViewInformation3D(); |
| maObjectTransformation.identity(); |
| maSdrSceneAttribute = drawinglayer::attribute::SdrSceneAttribute(); |
| maSdrLightingAttribute = drawinglayer::attribute::SdrLightingAttribute(); |
| } |
| |
| const drawinglayer::geometry::ViewInformation3D& ViewContactOfE3dScene::getViewInformation3D() const |
| { |
| if(maViewInformation3D.isDefault()) |
| { |
| // this version will create the content range on demand locally and thus is less |
| // performant than the other one. Since the information is buffered the planned |
| // behaviour is that the version with the given range is used initially. |
| basegfx::B3DRange aContentRange(getAllContentRange3D()); |
| |
| if(aContentRange.isEmpty()) |
| { |
| // empty scene, no 3d action should be necessary. Prepare some |
| // fallback size |
| OSL_ENSURE(false, "No need to get ViewInformation3D from an empty scene (!)"); |
| aContentRange.expand(basegfx::B3DPoint(-100.0, -100.0, -100.0)); |
| aContentRange.expand(basegfx::B3DPoint( 100.0, 100.0, 100.0)); |
| } |
| |
| const_cast < ViewContactOfE3dScene* >(this)->createViewInformation3D(aContentRange); |
| } |
| |
| return maViewInformation3D; |
| } |
| |
| const drawinglayer::geometry::ViewInformation3D& ViewContactOfE3dScene::getViewInformation3D(const basegfx::B3DRange& rContentRange) const |
| { |
| if(maViewInformation3D.isDefault()) |
| { |
| const_cast < ViewContactOfE3dScene* >(this)->createViewInformation3D(rContentRange); |
| } |
| |
| return maViewInformation3D; |
| } |
| |
| const basegfx::B2DHomMatrix& ViewContactOfE3dScene::getObjectTransformation() const |
| { |
| if(maObjectTransformation.isIdentity()) |
| { |
| const_cast < ViewContactOfE3dScene* >(this)->createObjectTransformation(); |
| } |
| |
| return maObjectTransformation; |
| } |
| |
| const drawinglayer::attribute::SdrSceneAttribute& ViewContactOfE3dScene::getSdrSceneAttribute() const |
| { |
| if(maSdrSceneAttribute.isDefault()) |
| { |
| const_cast < ViewContactOfE3dScene* >(this)->createSdrSceneAttribute(); |
| } |
| |
| return maSdrSceneAttribute; |
| } |
| |
| const drawinglayer::attribute::SdrLightingAttribute& ViewContactOfE3dScene::getSdrLightingAttribute() const |
| { |
| if(maSdrLightingAttribute.isDefault()) |
| { |
| const_cast < ViewContactOfE3dScene* >(this)->createSdrLightingAttribute(); |
| } |
| |
| return maSdrLightingAttribute; |
| } |
| |
| drawinglayer::primitive3d::Primitive3DSequence ViewContactOfE3dScene::getAllPrimitive3DSequence() const |
| { |
| drawinglayer::primitive3d::Primitive3DSequence aAllPrimitive3DSequence; |
| const sal_uInt32 nChildrenCount(GetObjectCount()); |
| |
| // add children recursively. Do NOT start with (*this), this would create |
| // a 3D transformPrimitive for the start scene. While this is theoretically not |
| // a bad thing, for historical reasons the transformation of the outmost scene |
| // is seen as part of the ViewTransformation (see text in createViewInformation3D) |
| for(sal_uInt32 a(0L); a < nChildrenCount; a++) |
| { |
| createSubPrimitive3DVector(GetViewContact(a), aAllPrimitive3DSequence, 0, 0, false); |
| } |
| |
| return aAllPrimitive3DSequence; |
| } |
| |
| basegfx::B3DRange ViewContactOfE3dScene::getAllContentRange3D() const |
| { |
| const drawinglayer::primitive3d::Primitive3DSequence xAllSequence(getAllPrimitive3DSequence()); |
| basegfx::B3DRange aAllContentRange3D; |
| |
| if(xAllSequence.hasElements()) |
| { |
| // for getting the 3D range using getB3DRangeFromPrimitive3DSequence a ViewInformation3D |
| // needs to be given for evtl. decompositions. Use a neutral ViewInformation3D here. This |
| // leaves all matrices on identity and the time on 0.0. |
| const uno::Sequence< beans::PropertyValue > aEmptyProperties; |
| const drawinglayer::geometry::ViewInformation3D aNeutralViewInformation3D(aEmptyProperties); |
| |
| aAllContentRange3D = drawinglayer::primitive3d::getB3DRangeFromPrimitive3DSequence(xAllSequence, aNeutralViewInformation3D); |
| } |
| |
| return aAllContentRange3D; |
| } |
| } // end of namespace contact |
| } // end of namespace sdr |
| |
| ////////////////////////////////////////////////////////////////////////////// |
| // eof |