Implementation on the issue 16186: EDF PAL 459: Mapping: when refining, to separate quadrangles into 2 triangles.

This commit is contained in:
rnv 2008-08-12 09:52:11 +00:00
parent 49922d93e3
commit 6fdc7dc872
18 changed files with 458 additions and 15 deletions

View File

@ -7,6 +7,7 @@
<li>\ref max_element_area_anchor "Max Element Area"</li>
<li>\ref length_from_edges_anchor "Length from Edges"</li>
<li>\ref quadrangle_preference_anchor "Quadrangle Preference"</li>
<li>\ref triangle_preference_anchor "Triangle Preference"</li>
</ul>
<br>
@ -48,4 +49,14 @@ otherwise this mesh will contain some triangular elements.
<br>
This hypothesis has one restriction on its work: the total quantity of
segments on all four sides of the face must be even (divisible by 2).
<br>
\anchor triangle_preference_anchor
<h2>Triangle Preference</h2>
This algorithm can be used only together with Quadrangle (Mapping)
algorithm. It allows to build triangular mesh faces in the refinement
area if the number of nodes at the opposite edges of a meshed face is not equal,
otherwise refinement area will contain some quadrangular elements.
<br>
*/

View File

@ -28,6 +28,7 @@ them, you operate numerical values):
<li>\ref max_element_area_anchor "Max Element Area"</li>
<li>\ref length_from_edges_anchor "Length from Edges"</li>
<li>\ref quadrangle_preference_anchor "Quadrangle Preference"</li>
<li>\ref triangle_preference_anchor "Triangle Preference"</li>
</ul>
<li>3D Hypothesis (for meshing of <b>volumes</b>):</li>
<ul>

View File

@ -18,6 +18,7 @@ allows to apply 1D, 2D, 3D meshing algorithms and a set of hypotheses:
<li>\ref max_element_area_anchor "Max Element Area"</li>
<li>\ref length_from_edges_anchor "Length from Edges"</li>
<li>\ref quadrangle_preference_anchor "Quadrangle Preference"</li>
<li>\ref triangle_preference_anchor "Triangle Preference"</li>
<li>\ref max_element_volume_hypo_page "Max Element Volume"</li>
</ul>
</li>

View File

@ -306,6 +306,16 @@ module StdMeshers
{
};
/*!
* StdMeshers_TrianglePreference: interface of "TrianglePreference" hypothesis.
* This hypothesis is used by StdMeshers_Quadrangle_2D algorithm.
* Presence of this hypothesis forces construction of triangles in the refinement
* area if the number of nodes on opposite edges is not the same.
*/
interface StdMeshers_TrianglePreference : SMESH::SMESH_Hypothesis
{
};
/*!
* StdMeshers_QuadraticMesh: interface of "QuadraticMesh" hypothesis.
* This is an auxiliary 1D hypothesis whose presence forces construction

View File

@ -63,6 +63,12 @@
auxiliary="true"
dim="2"/>
<hypothesis type="TrianglePreference"
label-id="Triangle Preference"
icon-id="mesh_algo_mefisto.png"
auxiliary="true"
dim="2"/>
<hypothesis type="QuadraticMesh"
label-id="Quadratic Mesh"
icon-id="mesh_algo_quad.png"
@ -150,7 +156,7 @@
<algorithm type="Quadrangle_2D"
label-id="Quadrangle (Mapping)"
icon-id="mesh_algo_quad.png"
opt-hypos="QuadranglePreference"
opt-hypos="QuadranglePreference,TrianglePreference"
input="EDGE"
output="QUAD"
dim="2"/>

View File

@ -1034,6 +1034,9 @@ Handle(_pyHypothesis) _pyHypothesis::NewHypothesis( const Handle(_pyCommand)& th
hyp->SetConvMethodAndType( "QuadranglePreference", "Quadrangle_2D");
hyp->SetConvMethodAndType( "QuadranglePreference", "NETGEN_2D_ONLY");
}
else if ( hypType == "TrianglePreference" ) {
hyp->SetConvMethodAndType( "TrianglePreference", "Quadrangle_2D");
}
// NETGEN ----------
// else if ( hypType == "NETGEN_2D") { // 1D-2D
// algo->SetConvMethodAndType( "Triangle" , hypType.ToCString());

View File

@ -3428,6 +3428,16 @@ class Mesh_Quadrangle(Mesh_Algorithm):
CompareMethod=self.CompareEqualHyp)
return hyp
## Defines "TrianglePreference" hypothesis, forcing construction
# of triangles in the refinement area if the number of nodes
# on the opposite edges is not the same
#
# @ingroup l3_hypos_additi
def TrianglePreference(self):
hyp = self.Hypothesis("TrianglePreference", UseExisting=1,
CompareMethod=self.CompareEqualHyp)
return hyp
# Public class: Mesh_Tetrahedron
# ------------------------------

View File

@ -64,7 +64,8 @@ salomeinclude_HEADERS = \
StdMeshers_CompositeSegment_1D.hxx \
StdMeshers_UseExisting_1D2D.hxx \
StdMeshers_QuadToTriaAdaptor.hxx \
SMESH_StdMeshers.hxx
SMESH_StdMeshers.hxx \
StdMeshers_TrianglePreference.hxx
# Libraries targets
@ -106,7 +107,8 @@ dist_libStdMeshers_la_SOURCES = \
StdMeshers_FaceSide.cxx \
StdMeshers_CompositeSegment_1D.cxx \
StdMeshers_UseExisting_1D2D.cxx \
StdMeshers_QuadToTriaAdaptor.cxx
StdMeshers_QuadToTriaAdaptor.cxx \
StdMeshers_TrianglePreference.cxx
# additionnal information to compil and link file

View File

@ -83,6 +83,7 @@ StdMeshers_Quadrangle_2D::StdMeshers_Quadrangle_2D (int hypId, int studyId, SMES
_name = "Quadrangle_2D";
_shapeType = (1 << TopAbs_FACE);
_compatibleHypothesis.push_back("QuadranglePreference");
_compatibleHypothesis.push_back("TrianglePreference");
myTool = 0;
}
@ -111,10 +112,25 @@ bool StdMeshers_Quadrangle_2D::CheckHypothesis
bool isOk = true;
aStatus = SMESH_Hypothesis::HYP_OK;
// there is only one compatible Hypothesis so far
const list <const SMESHDS_Hypothesis * >&hyps = GetUsedHypothesis(aMesh, aShape, false);
myQuadranglePreference = hyps.size() > 0;
const list <const SMESHDS_Hypothesis * >&hyps = GetUsedHypothesis(aMesh, aShape, false);
const SMESHDS_Hypothesis *theHyp = 0;
if(hyps.size() > 0){
theHyp = *hyps.begin();
if(strcmp("QuadranglePreference", theHyp->GetName()) == 0) {
myQuadranglePreference= true;
myTrianglePreference= false;
}
else if(strcmp("TrianglePreference", theHyp->GetName()) == 0){
myQuadranglePreference= false;
myTrianglePreference= true;
}
}
else {
myQuadranglePreference = false;
myTrianglePreference = false;
}
return isOk;
}
@ -307,8 +323,17 @@ bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh,
else
d = quad->uv_grid[nbhoriz + near - 1].node;
//SMDS_MeshFace* face = meshDS->AddFace(a, b, c, d);
SMDS_MeshFace* face = myTool->AddFace(a, b, c, d);
meshDS->SetMeshElementOnShape(face, geomFaceID);
if(!myTrianglePreference){
SMDS_MeshFace* face = myTool->AddFace(a, b, c, d);
meshDS->SetMeshElementOnShape(face, geomFaceID);
}
else {
SMDS_MeshFace* face = myTool->AddFace(a, b, c);
meshDS->SetMeshElementOnShape(face, geomFaceID);
face = myTool->AddFace(a, c, d);
meshDS->SetMeshElementOnShape(face, geomFaceID);
}
// if node d is not at position g - make additional triangles
if (near - 1 > g) {
@ -391,8 +416,16 @@ bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh,
else
d = quad->uv_grid[nbhoriz*(nbvertic - 2) + near + 1].node;
//SMDS_MeshFace* face = meshDS->AddFace(a, b, c, d);
SMDS_MeshFace* face = myTool->AddFace(a, b, c, d);
meshDS->SetMeshElementOnShape(face, geomFaceID);
if(!myTrianglePreference){
SMDS_MeshFace* face = myTool->AddFace(a, b, c, d);
meshDS->SetMeshElementOnShape(face, geomFaceID);
}
else {
SMDS_MeshFace* face = myTool->AddFace(a, b, c);
meshDS->SetMeshElementOnShape(face, geomFaceID);
face = myTool->AddFace(a, c, d);
meshDS->SetMeshElementOnShape(face, geomFaceID);
}
if (near + 1 < g) { // if d not is at g - make additional triangles
for (int k = near + 1; k < g; k++) {
@ -460,8 +493,17 @@ bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh,
else
d = quad->uv_grid[nbhoriz*near - 2].node;
//SMDS_MeshFace* face = meshDS->AddFace(a, b, c, d);
SMDS_MeshFace* face = myTool->AddFace(a, b, c, d);
meshDS->SetMeshElementOnShape(face, geomFaceID);
if(!myTrianglePreference){
SMDS_MeshFace* face = myTool->AddFace(a, b, c, d);
meshDS->SetMeshElementOnShape(face, geomFaceID);
}
else {
SMDS_MeshFace* face = myTool->AddFace(a, b, c);
meshDS->SetMeshElementOnShape(face, geomFaceID);
face = myTool->AddFace(a, c, d);
meshDS->SetMeshElementOnShape(face, geomFaceID);
}
if (near - 1 > g) { // if d not is at g - make additional triangles
for (int k = near - 1; k > g; k--) {
@ -526,8 +568,16 @@ bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh,
else
d = quad->uv_grid[nbhoriz*(near + 1) + 1].node;
//SMDS_MeshFace* face = meshDS->AddFace(a, b, c, d);
SMDS_MeshFace* face = myTool->AddFace(a, b, c, d);
meshDS->SetMeshElementOnShape(face, geomFaceID);
if(!myTrianglePreference){
SMDS_MeshFace* face = myTool->AddFace(a, b, c, d);
meshDS->SetMeshElementOnShape(face, geomFaceID);
}
else {
SMDS_MeshFace* face = myTool->AddFace(a, b, c);
meshDS->SetMeshElementOnShape(face, geomFaceID);
face = myTool->AddFace(a, c, d);
meshDS->SetMeshElementOnShape(face, geomFaceID);
}
if (near + 1 < g) { // if d not is at g - make additional triangles
for (int k = near + 1; k < g; k++) {

View File

@ -103,6 +103,8 @@ protected:
// is not the same in the case where the global number of nodes on edges is even
bool myQuadranglePreference;
bool myTrianglePreference;
SMESH_MesherHelper* myTool; // tool for working with quadratic elements
};

View File

@ -0,0 +1,116 @@
// SMESH StdMeshers_TrianglePreference
//
// Copyright (C) 2003 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
//
//
//
// File : StdMeshers_TrianglePreference.cxx
// Module : SMESH
// $Header$
#include "StdMeshers_TrianglePreference.hxx"
#include "utilities.h"
using namespace std;
//=============================================================================
/*!
*
*/
//=============================================================================
StdMeshers_TrianglePreference::StdMeshers_TrianglePreference(int hypId,
int studyId,
SMESH_Gen * gen)
:SMESH_Hypothesis(hypId, studyId, gen)
{
_name = "TrianglePreference";
_param_algo_dim = -2; // auxiliary used by StdMeshers_Quadrangle_2D
}
//=============================================================================
/*!
*
*/
//=============================================================================
StdMeshers_TrianglePreference::~StdMeshers_TrianglePreference()
{
}
//=============================================================================
/*!
*
*/
//=============================================================================
ostream & StdMeshers_TrianglePreference::SaveTo(ostream & save)
{
return save;
}
//=============================================================================
/*!
*
*/
//=============================================================================
istream & StdMeshers_TrianglePreference::LoadFrom(istream & load)
{
return load;
}
//=============================================================================
/*!
*
*/
//=============================================================================
ostream & operator <<(ostream & save, StdMeshers_TrianglePreference & hyp)
{
return hyp.SaveTo( save );
}
//=============================================================================
/*!
*
*/
//=============================================================================
istream & operator >>(istream & load, StdMeshers_TrianglePreference & hyp)
{
return hyp.LoadFrom( load );
}
//================================================================================
/*!
* \brief Initialize my parameter values by the mesh built on the geometry
* \param theMesh - the built mesh
* \param theShape - the geometry of interest
* \retval bool - true if parameter values have been successfully defined
*
* Just return false as this hypothesis does not have parameters values
*/
//================================================================================
bool StdMeshers_TrianglePreference::SetParametersByMesh(const SMESH_Mesh* /*theMesh*/,
const TopoDS_Shape& /*theShape*/)
{
return false;
}

View File

@ -0,0 +1,64 @@
// SMESH StdMeshers : implementaion of SMESH idl descriptions
//
// Copyright (C) 2003 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
//
//
//
// File : StdMeshers_TrianglePreference.hxx
// Module : SMESH
// $Header$
#ifndef _StdMeshers_TrianglePreference_HXX_
#define _StdMeshers_TrianglePreference_HXX_
#include "SMESH_StdMeshers.hxx"
#include "SMESH_Hypothesis.hxx"
#include "Utils_SALOME_Exception.hxx"
/*!
* \brief Hypothesis for StdMeshers_Quadrangle_2D, forcing construction
* of triangles in the in a refinement area if the number of nodes
* on opposite edges is not the same. See Issue 16186.
*/
class STDMESHERS_EXPORT StdMeshers_TrianglePreference:public SMESH_Hypothesis
{
public:
StdMeshers_TrianglePreference(int hypId, int studyId, SMESH_Gen * gen);
virtual ~ StdMeshers_TrianglePreference();
virtual std::ostream & SaveTo(std::ostream & save);
virtual std::istream & LoadFrom(std::istream & load);
friend std::ostream & operator <<(std::ostream & save, StdMeshers_TrianglePreference & hyp);
friend std::istream & operator >>(std::istream & load, StdMeshers_TrianglePreference & hyp);
/*!
* \brief Initialize my parameter values by the mesh built on the geometry
* \param theMesh - the built mesh
* \param theShape - the geometry of interest
* \retval bool - true if parameter values have been successfully defined
*
* Just return false as this hypothesis does not have parameters values
*/
virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape);
};
#endif

View File

@ -110,6 +110,10 @@ msgstr "mesh_tree_hypo_area.png"
msgid "ICON_SMESH_TREE_HYPO_QuadranglePreference"
msgstr "mesh_tree_algo_quad.png"
#mesh_tree_hypo_trianglepreference
msgid "ICON_SMESH_TREE_HYPO_TrianglePreference"
msgstr "mesh_tree_algo_mefisto.png"
#mesh_tree_hypo_quadraticmesh
msgid "ICON_SMESH_TREE_HYPO_QuadraticMesh"
msgstr "mesh_tree_hypo_length.png"

View File

@ -170,6 +170,10 @@
<source>ICON_SMESH_TREE_HYPO_QuadranglePreference</source>
<translation>mesh_tree_algo_quad.png</translation>
</message>
<message>
<source>ICON_SMESH_TREE_HYPO_TrianglePreference</source>
<translation>mesh_tree_algo_mefisto.png</translation>
</message>
<message>
<source>ICON_SMESH_TREE_HYPO_QuadraticMesh</source>
<translation>mesh_tree_hypo_length.png</translation>

View File

@ -58,6 +58,7 @@ salomeinclude_HEADERS = \
StdMeshers_CompositeSegment_1D_i.hxx \
StdMeshers_SegmentAroundVertex_0D_i.hxx \
StdMeshers_SegmentLengthAroundVertex_i.hxx \
StdMeshers_TrianglePreference_i.hxx \
SMESH_StdMeshers_I.hxx
# Libraries targets
@ -93,7 +94,8 @@ dist_libStdMeshersEngine_la_SOURCES = \
StdMeshers_CompositeSegment_1D_i.cxx \
StdMeshers_SegmentAroundVertex_0D_i.cxx \
StdMeshers_SegmentLengthAroundVertex_i.cxx \
StdMeshers_UseExisting_1D2D_i.cxx
StdMeshers_UseExisting_1D2D_i.cxx \
StdMeshers_TrianglePreference_i.cxx
# additionnal information to compil and link file
libStdMeshersEngine_la_CPPFLAGS = \

View File

@ -0,0 +1,95 @@
// Copyright (C) 2008 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
//
//
//
// File : StdMeshers_TrianglePreference_i.cxx
// Author :
// Module : SMESH
#include "StdMeshers_TrianglePreference_i.hxx"
#include "SMESH_Gen_i.hxx"
#include "SMESH_Gen.hxx"
#include "Utils_CorbaException.hxx"
#include "utilities.h"
#include <TCollection_AsciiString.hxx>
using namespace std;
//=============================================================================
/*!
* StdMeshers_TrianglePreference_i::StdMeshers_TrianglePreference_i
*
* Constructor
*/
//=============================================================================
StdMeshers_TrianglePreference_i::StdMeshers_TrianglePreference_i
( PortableServer::POA_ptr thePOA,
int theStudyId,
::SMESH_Gen* theGenImpl ): SALOME::GenericObj_i( thePOA ),
SMESH_Hypothesis_i( thePOA )
{
myBaseImpl = new ::StdMeshers_TrianglePreference( theGenImpl->GetANewId(),
theStudyId,
theGenImpl );
}
//=============================================================================
/*!
* StdMeshers_TrianglePreference_i::~StdMeshers_TrianglePreference_i
*
* Destructor
*/
//=============================================================================
StdMeshers_TrianglePreference_i::~StdMeshers_TrianglePreference_i()
{
}
//=============================================================================
/*!
* StdMeshers_TrianglePreference_i::GetImpl
*
* Get implementation
*/
//=============================================================================
::StdMeshers_TrianglePreference* StdMeshers_TrianglePreference_i::GetImpl()
{
return ( ::StdMeshers_TrianglePreference* )myBaseImpl;
}
//================================================================================
/*!
* \brief Verify whether hypothesis supports given entity type
* \param type - dimension (see SMESH::Dimension enumeration)
* \retval CORBA::Boolean - TRUE if dimension is supported, FALSE otherwise
*
* Verify whether hypothesis supports given entity type (see SMESH::Dimension enumeration)
*/
//================================================================================
CORBA::Boolean StdMeshers_TrianglePreference_i::IsDimSupported( SMESH::Dimension type )
{
return type == SMESH::DIM_2D;
}

View File

@ -0,0 +1,59 @@
// Copyright (C) 2008 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
//
//
//
// File : StdMeshers_TrianglePreference_i.hxx
// Author :
// Module : SMESH
#ifndef _SMESH_TrianglePreference_I_HXX_
#define _SMESH_TrianglePreference_I_HXX_
#include "SMESH_StdMeshers_I.hxx"
#include <SALOMEconfig.h>
#include CORBA_SERVER_HEADER(SMESH_BasicHypothesis)
#include "SMESH_Hypothesis_i.hxx"
#include "StdMeshers_TrianglePreference.hxx"
class SMESH_Gen;
class STDMESHERS_I_EXPORT StdMeshers_TrianglePreference_i:
public virtual POA_StdMeshers::StdMeshers_TrianglePreference,
public virtual SMESH_Hypothesis_i
{
public:
// Constructor
StdMeshers_TrianglePreference_i( PortableServer::POA_ptr thePOA,
int theStudyId,
::SMESH_Gen* theGenImpl );
// Destructor
virtual ~StdMeshers_TrianglePreference_i();
// Get implementation
::StdMeshers_TrianglePreference* GetImpl();
// Verify whether hypothesis supports given entity type
CORBA::Boolean IsDimSupported( SMESH::Dimension type );
};
#endif //_SMESH_TrianglePreference_I_HXX_

View File

@ -40,6 +40,7 @@
#include "StdMeshers_Propagation_i.hxx"
#include "StdMeshers_LengthFromEdges_i.hxx"
#include "StdMeshers_QuadranglePreference_i.hxx"
#include "StdMeshers_TrianglePreference_i.hxx"
#include "StdMeshers_QuadraticMesh_i.hxx"
#include "StdMeshers_MaxElementArea_i.hxx"
#include "StdMeshers_MaxElementVolume_i.hxx"
@ -108,6 +109,8 @@ STDMESHERS_I_EXPORT
aCreator = new StdHypothesisCreator_i<StdMeshers_AutomaticLength_i>;
else if (strcmp(aHypName, "QuadranglePreference") == 0)
aCreator = new StdHypothesisCreator_i<StdMeshers_QuadranglePreference_i>;
else if (strcmp(aHypName, "TrianglePreference") == 0)
aCreator = new StdHypothesisCreator_i<StdMeshers_TrianglePreference_i>;
else if (strcmp(aHypName, "QuadraticMesh") == 0)
aCreator = new StdHypothesisCreator_i<StdMeshers_QuadraticMesh_i>;
else if (strcmp(aHypName, "ProjectionSource3D") == 0)